Class: Gitlab::QueryLimiting::Transaction
- Inherits:
-
Object
- Object
- Gitlab::QueryLimiting::Transaction
- Defined in:
- lib/gitlab/query_limiting/transaction.rb
Constant Summary collapse
- THREAD_KEY =
:__gitlab_query_counts_transaction- ThresholdExceededError =
Error that is raised whenever exceeding the maximum number of queries.
Class.new(StandardError)
- GEO_NODES_LOAD =
'SELECT 1 AS one FROM "geo_nodes" LIMIT 1'- LICENSES_LOAD =
'SELECT "licenses".* FROM "licenses" ORDER BY "licenses"."id"'- SCHEMA_INTROSPECTION =
%r{SELECT.*(FROM|JOIN) (pg_attribute|pg_class)}m- SAVEPOINT =
%r{(RELEASE )?SAVEPOINT}m- SET =
%r{^SET\s}m- SHOW =
%r{^SHOW\s}m
Instance Attribute Summary collapse
-
#action ⇒ Object
The name of the action (e.g. ‘UsersController#show`) that is being executed.
-
#count ⇒ Object
Returns the value of attribute count.
Class Method Summary collapse
- .current ⇒ Object
-
.default_threshold ⇒ Object
The maximum number of SQL queries that can be executed in a request.
-
.run ⇒ Object
Starts a new transaction and returns it and the blocks’ return value.
-
.threshold ⇒ Object
Deprecated, use default_threshold.
Instance Method Summary collapse
-
#act_upon_results ⇒ Object
Sends a notification based on the number of executed SQL queries.
- #enabled? ⇒ Boolean
- #error_message ⇒ Object
- #executed_sql(sql) ⇒ Object
-
#ignorable?(sql) ⇒ Boolean
queries can be safely ignored if they are amoritized in regular usage (i.e. only requested occasionally and otherwise cached).
- #increment(sql = nil) ⇒ Object
-
#initialize ⇒ Transaction
constructor
A new instance of Transaction.
- #log_threshold ⇒ Object
- #raise_error? ⇒ Boolean
- #threshold ⇒ Object
- #threshold_exceeded? ⇒ Boolean
Constructor Details
#initialize ⇒ Transaction
Returns a new instance of Transaction.
53 54 55 56 57 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 53 def initialize @action = nil @count = 0 @sql_executed = [] end |
Instance Attribute Details
#action ⇒ Object
The name of the action (e.g. ‘UsersController#show`) that is being executed.
12 13 14 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 12 def action @action end |
#count ⇒ Object
Returns the value of attribute count.
8 9 10 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 8 def count @count end |
Class Method Details
.current ⇒ Object
29 30 31 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 29 def self.current Thread.current[THREAD_KEY] end |
.default_threshold ⇒ Object
The maximum number of SQL queries that can be executed in a request. For the sake of keeping things simple we hardcode this value here, it’s not supposed to be changed very often anyway.
17 18 19 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 17 def self.default_threshold 100 end |
.run ⇒ Object
Starts a new transaction and returns it and the blocks’ return value.
Example:
transaction, retval = Transaction.run do
10
end
retval # => 10
42 43 44 45 46 47 48 49 50 51 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 42 def self.run previous_transaction = current transaction = new Thread.current[THREAD_KEY] = transaction [transaction, yield] ensure Thread.current[THREAD_KEY] = previous_transaction end |
.threshold ⇒ Object
Deprecated, use default_threshold
22 23 24 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 22 def self.threshold default_threshold end |
Instance Method Details
#act_upon_results ⇒ Object
Sends a notification based on the number of executed SQL queries.
60 61 62 63 64 65 66 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 60 def act_upon_results return unless threshold_exceeded? error = ThresholdExceededError.new() raise(error) if raise_error? end |
#enabled? ⇒ Boolean
124 125 126 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 124 def enabled? ::Gitlab::QueryLimiting.enabled? end |
#error_message ⇒ Object
114 115 116 117 118 119 120 121 122 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 114 def header = 'Too many SQL queries were executed' header = "#{header} in #{action}" if action msg = "a maximum of #{threshold} is allowed but #{count} SQL queries were executed" log = @sql_executed.each_with_index.map { |sql, i| "#{i}: #{sql}" }.join("\n").presence ellipsis = '...' if @count > log_threshold ["#{header}: #{msg}", log, ellipsis].compact.join("\n") end |
#executed_sql(sql) ⇒ Object
92 93 94 95 96 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 92 def executed_sql(sql) return if @count > log_threshold || ignorable?(sql) @sql_executed << sql end |
#ignorable?(sql) ⇒ Boolean
queries can be safely ignored if they are amoritized in regular usage (i.e. only requested occasionally and otherwise cached).
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 81 def ignorable?(sql) return true if sql&.include?(GEO_NODES_LOAD) return true if sql&.include?(LICENSES_LOAD) return true if SCHEMA_INTROSPECTION.match?(sql) return true if SAVEPOINT.match?(sql) return true if SET.match?(sql) return true if SHOW.match?(sql) false end |
#increment(sql = nil) ⇒ Object
68 69 70 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 68 def increment(sql = nil) @count += 1 if enabled? && !ignorable?(sql) end |
#log_threshold ⇒ Object
106 107 108 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 106 def log_threshold threshold * 1.5 end |
#raise_error? ⇒ Boolean
98 99 100 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 98 def raise_error? Rails.env.test? end |
#threshold ⇒ Object
102 103 104 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 102 def threshold ::Gitlab::QueryLimiting.threshold || self.class.threshold end |
#threshold_exceeded? ⇒ Boolean
110 111 112 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 110 def threshold_exceeded? count > threshold end |