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
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
- .log_threshold ⇒ Object
-
.run ⇒ Object
Starts a new transaction and returns it and the blocks’ return value.
-
.threshold ⇒ Object
The maximum number of SQL queries that can be executed in a request.
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.
- #raise_error? ⇒ Boolean
- #threshold_exceeded? ⇒ Boolean
Constructor Details
#initialize ⇒ Transaction
Returns a new instance of Transaction.
50 51 52 53 54 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 50 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
28 29 30 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 28 def self.current Thread.current[THREAD_KEY] end |
.log_threshold ⇒ Object
21 22 23 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 21 def self.log_threshold threshold * 1.5 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
41 42 43 44 45 46 47 48 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 41 def self.run transaction = new Thread.current[THREAD_KEY] = transaction [transaction, yield] ensure Thread.current[THREAD_KEY] = nil end |
.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.threshold 100 end |
Instance Method Details
#act_upon_results ⇒ Object
Sends a notification based on the number of executed SQL queries.
57 58 59 60 61 62 63 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 57 def act_upon_results return unless threshold_exceeded? error = ThresholdExceededError.new() raise(error) if raise_error? end |
#enabled? ⇒ Boolean
107 108 109 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 107 def enabled? ::Gitlab::QueryLimiting.enabled? end |
#error_message ⇒ Object
97 98 99 100 101 102 103 104 105 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 97 def header = 'Too many SQL queries were executed' header = "#{header} in #{action}" if action msg = "a maximum of #{self.class.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 > self.class.log_threshold ["#{header}: #{msg}", log, ellipsis].compact.join("\n") end |
#executed_sql(sql) ⇒ Object
83 84 85 86 87 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 83 def executed_sql(sql) return if @count > self.class.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).
75 76 77 78 79 80 81 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 75 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) false end |
#increment(sql = nil) ⇒ Object
65 66 67 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 65 def increment(sql = nil) @count += 1 if enabled? && !ignorable?(sql) end |
#raise_error? ⇒ Boolean
89 90 91 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 89 def raise_error? Rails.env.test? end |
#threshold_exceeded? ⇒ Boolean
93 94 95 |
# File 'lib/gitlab/query_limiting/transaction.rb', line 93 def threshold_exceeded? count > self.class.threshold end |