Skip to content

Commit 3fcadfb

Browse files
authored
Merge pull request rails#43598 from Shopify/active-support-execution-context
Extract ActiveSupport::ExecutionContext out of ActiveRecord::QueryLogs
2 parents f5a7d2e + 6bad959 commit 3fcadfb

File tree

16 files changed

+151
-141
lines changed

16 files changed

+151
-141
lines changed

actionpack/lib/abstract_controller/base.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ def process(action, *args)
148148

149149
@_response_body = nil
150150

151+
ActiveSupport::ExecutionContext[:controller] = self
151152
process_action(action_name, *args)
152153
end
153154

actionpack/lib/action_controller.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ module ActionController
3737
autoload :Logging
3838
autoload :MimeResponds
3939
autoload :ParamsWrapper
40-
autoload :QueryTags
4140
autoload :Redirecting
4241
autoload :Renderers
4342
autoload :Rendering

actionpack/lib/action_controller/metal/query_tags.rb

Lines changed: 0 additions & 16 deletions
This file was deleted.

actionpack/lib/action_controller/railtie.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,6 @@ class Railtie < Rails::Railtie # :nodoc:
113113
if query_logs_tags_enabled
114114
app.config.active_record.query_log_tags += [:controller, :action]
115115

116-
ActiveSupport.on_load(:action_controller) do
117-
include ActionController::QueryTags
118-
end
119-
120116
ActiveSupport.on_load(:active_record) do
121117
ActiveRecord::QueryLogs.taggings.merge!(
122118
controller: ->(context) { context[:controller]&.controller_name },

activejob/lib/active_job/execution.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def perform(*)
5454

5555
private
5656
def _perform_job
57+
ActiveSupport::ExecutionContext[:job] = self
5758
run_callbacks :perform do
5859
perform(*arguments)
5960
end

activejob/lib/active_job/query_tags.rb

Lines changed: 0 additions & 16 deletions
This file was deleted.

activejob/lib/active_job/railtie.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,6 @@ class Railtie < Rails::Railtie # :nodoc:
6565
if query_logs_tags_enabled
6666
app.config.active_record.query_log_tags << :job
6767

68-
ActiveSupport.on_load(:active_job) do
69-
include ActiveJob::QueryTags
70-
end
71-
7268
ActiveSupport.on_load(:active_record) do
7369
ActiveRecord::QueryLogs.taggings[:job] = ->(context) { context[:job].class.name if context[:job] }
7470
end

activerecord/lib/active_record/query_logs.rb

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,17 @@ module ActiveRecord
4444
# ]
4545
# ActiveRecord::QueryLogs.tags = tags
4646
#
47-
# The QueryLogs +context+ can be manipulated via the +set_context+ method.
47+
# The QueryLogs +context+ can be manipulated via the +ActiveSupport::ExecutionContext.set+ method.
4848
#
4949
# Temporary updates limited to the execution of a block:
5050
#
51-
# ActiveRecord::QueryLogs.set_context(foo: Bar.new) do
51+
# ActiveSupport::ExecutionContext.set(foo: Bar.new) do
5252
# posts = Post.all
5353
# end
5454
#
5555
# Direct updates to a context value:
5656
#
57-
# ActiveRecord::QueryLogs.set_context(foo: Bar.new)
57+
# ActiveSupport::ExecutionContext[:foo] = Bar.new
5858
#
5959
# Tag comments can be prepended to the query:
6060
#
@@ -76,30 +76,6 @@ module QueryLogs
7676
thread_mattr_accessor :cached_comment, instance_accessor: false
7777

7878
class << self
79-
# Updates the context used to construct tags in the SQL comment.
80-
# If a block is given, it resets the provided keys to their
81-
# previous value once the block exits.
82-
def set_context(**options)
83-
options.symbolize_keys!
84-
85-
keys = options.keys
86-
previous_context = keys.zip(context.values_at(*keys)).to_h
87-
context.merge!(options)
88-
self.cached_comment = nil
89-
if block_given?
90-
begin
91-
yield
92-
ensure
93-
context.merge!(previous_context)
94-
self.cached_comment = nil
95-
end
96-
end
97-
end
98-
99-
def clear_context # :nodoc:
100-
context.clear
101-
end
102-
10379
def call(sql) # :nodoc:
10480
if prepend_comment
10581
"#{self.comment} #{sql}"
@@ -108,6 +84,12 @@ def call(sql) # :nodoc:
10884
end.strip
10985
end
11086

87+
def clear_cache # :nodoc:
88+
self.cached_comment = nil
89+
end
90+
91+
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
92+
11193
private
11294
# Returns an SQL comment +String+ containing the query log tags.
11395
# Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
@@ -126,15 +108,13 @@ def uncached_comment
126108
end
127109
end
128110

129-
def context
130-
Thread.current[:active_record_query_log_tags_context] ||= {}
131-
end
132-
133111
def escape_sql_comment(content)
134112
content.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
135113
end
136114

137115
def tag_content
116+
context = ActiveSupport::ExecutionContext.to_h
117+
138118
tags.flat_map { |i| [*i] }.filter_map do |tag|
139119
key, handler = tag
140120
handler ||= taggings[key]

activerecord/lib/active_record/railtie.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,10 +376,6 @@ class Railtie < Rails::Railtie # :nodoc:
376376
if app.config.active_record.cache_query_log_tags
377377
ActiveRecord::QueryLogs.cache_query_log_tags = true
378378
end
379-
380-
app.reloader.before_class_unload { ActiveRecord::QueryLogs.clear_context }
381-
app.executor.to_run { ActiveRecord::QueryLogs.clear_context }
382-
app.executor.to_complete { ActiveRecord::QueryLogs.clear_context }
383379
end
384380
end
385381
end

activerecord/test/cases/query_logs_test.rb

Lines changed: 13 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ class QueryLogsTest < ActiveRecord::TestCase
1111
}
1212

1313
def setup
14-
# QueryLogs context is automatically reset in Rails app via an executor hooks set in railtie
14+
# ActiveSupport::ExecutionContext context is automatically reset in Rails app via an executor hooks set in railtie
1515
# But not in Active Record's own test suite.
16-
ActiveRecord::QueryLogs.clear_context
16+
ActiveSupport::ExecutionContext.clear
1717

1818
# Enable the query tags logging
1919
@original_transformers = ActiveRecord.query_transformers
2020
@original_prepend = ActiveRecord::QueryLogs.prepend_comment
21+
@original_tags = ActiveRecord::QueryLogs.tags
2122
ActiveRecord.query_transformers += [ActiveRecord::QueryLogs]
2223
ActiveRecord::QueryLogs.prepend_comment = false
2324
ActiveRecord::QueryLogs.cache_query_log_tags = false
@@ -27,10 +28,13 @@ def setup
2728
def teardown
2829
ActiveRecord.query_transformers = @original_transformers
2930
ActiveRecord::QueryLogs.prepend_comment = @original_prepend
30-
ActiveRecord::QueryLogs.tags = []
31-
# QueryLogs context is automatically reset in Rails app via an executor hooks set in railtie
31+
ActiveRecord::QueryLogs.tags = @original_tags
32+
ActiveRecord::QueryLogs.prepend_comment = false
33+
ActiveRecord::QueryLogs.cache_query_log_tags = false
34+
ActiveRecord::QueryLogs.cached_comment = nil
35+
# ActiveSupport::ExecutionContext context is automatically reset in Rails app via an executor hooks set in railtie
3236
# But not in Active Record's own test suite.
33-
ActiveRecord::QueryLogs.clear_context
37+
ActiveSupport::ExecutionContext.clear
3438
end
3539

3640
def test_escaping_good_comment
@@ -57,8 +61,6 @@ def test_add_comments_to_beginning_of_query
5761
assert_sql(%r{/\*application:active_record\*/ select id from posts$}) do
5862
ActiveRecord::Base.connection.execute "select id from posts"
5963
end
60-
ensure
61-
ActiveRecord::QueryLogs.prepend_comment = nil
6264
end
6365

6466
def test_exists_is_commented
@@ -112,41 +114,24 @@ def test_retrieves_comment_from_cache_when_enabled_and_set
112114
ActiveRecord::QueryLogs.stub(:cached_comment, "/*cached_comment*/") do
113115
assert_equal "/*cached_comment*/", ActiveRecord::QueryLogs.call("")
114116
end
115-
ensure
116-
ActiveRecord::QueryLogs.cached_comment = nil
117-
ActiveRecord::QueryLogs.cache_query_log_tags = false
118117
end
119118

120119
def test_resets_cache_on_context_update
121120
ActiveRecord::QueryLogs.cache_query_log_tags = true
122-
ActiveRecord::QueryLogs.set_context(temporary: "value")
121+
ActiveSupport::ExecutionContext[:temporary] = "value"
123122
ActiveRecord::QueryLogs.tags = [ temporary_tag: ->(context) { context[:temporary] } ]
124123

125124
assert_equal "/*temporary_tag:value*/", ActiveRecord::QueryLogs.call("")
126125

127-
ActiveRecord::QueryLogs.set_context(temporary: "new_value")
126+
ActiveSupport::ExecutionContext[:temporary] = "new_value"
128127

129128
assert_nil ActiveRecord::QueryLogs.cached_comment
130129
assert_equal "/*temporary_tag:new_value*/", ActiveRecord::QueryLogs.call("")
131-
ensure
132-
ActiveRecord::QueryLogs.cached_comment = nil
133-
ActiveRecord::QueryLogs.cache_query_log_tags = false
134-
end
135-
136-
def test_ensure_context_has_symbol_keys
137-
ActiveRecord::QueryLogs.tags = [ new_key: ->(context) { context[:symbol_key] } ]
138-
ActiveRecord::QueryLogs.set_context("symbol_key" => "symbolized")
139-
140-
assert_sql(%r{/\*new_key:symbolized}) do
141-
Dashboard.first
142-
end
143-
ensure
144-
ActiveRecord::QueryLogs.set_context(application_name: nil)
145130
end
146131

147132
def test_default_tag_behavior
148133
ActiveRecord::QueryLogs.tags = [:application, :foo]
149-
ActiveRecord::QueryLogs.set_context(foo: "bar") do
134+
ActiveSupport::ExecutionContext.set(foo: "bar") do
150135
assert_sql(%r{/\*application:active_record,foo:bar\*/}) do
151136
Dashboard.first
152137
end
@@ -157,39 +142,29 @@ def test_default_tag_behavior
157142
end
158143

159144
def test_empty_comments_are_not_added
160-
original_tags = ActiveRecord::QueryLogs.tags
161145
ActiveRecord::QueryLogs.tags = [ empty: -> { nil } ]
162146
assert_sql(%r{select id from posts$}) do
163147
ActiveRecord::Base.connection.execute "select id from posts"
164148
end
165-
ensure
166-
ActiveRecord::QueryLogs.tags = original_tags
167149
end
168150

169151
def test_custom_basic_tags
170-
original_tags = ActiveRecord::QueryLogs.tags
171152
ActiveRecord::QueryLogs.tags = [ :application, { custom_string: "test content" } ]
172153

173154
assert_sql(%r{/\*application:active_record,custom_string:test content\*/$}) do
174155
Dashboard.first
175156
end
176-
ensure
177-
ActiveRecord::QueryLogs.tags = original_tags
178157
end
179158

180159
def test_custom_proc_tags
181-
original_tags = ActiveRecord::QueryLogs.tags
182160
ActiveRecord::QueryLogs.tags = [ :application, { custom_proc: -> { "test content" } } ]
183161

184162
assert_sql(%r{/\*application:active_record,custom_proc:test content\*/$}) do
185163
Dashboard.first
186164
end
187-
ensure
188-
ActiveRecord::QueryLogs.tags = original_tags
189165
end
190166

191167
def test_multiple_custom_tags
192-
original_tags = ActiveRecord::QueryLogs.tags
193168
ActiveRecord::QueryLogs.tags = [
194169
:application,
195170
{ custom_proc: -> { "test content" }, another_proc: -> { "more test content" } },
@@ -198,34 +173,14 @@ def test_multiple_custom_tags
198173
assert_sql(%r{/\*application:active_record,custom_proc:test content,another_proc:more test content\*/$}) do
199174
Dashboard.first
200175
end
201-
ensure
202-
ActiveRecord::QueryLogs.tags = original_tags
203176
end
204177

205178
def test_custom_proc_context_tags
206-
original_tags = ActiveRecord::QueryLogs.tags
207-
ActiveRecord::QueryLogs.set_context(foo: "bar")
179+
ActiveSupport::ExecutionContext[:foo] = "bar"
208180
ActiveRecord::QueryLogs.tags = [ :application, { custom_context_proc: ->(context) { context[:foo] } } ]
209181

210182
assert_sql(%r{/\*application:active_record,custom_context_proc:bar\*/$}) do
211183
Dashboard.first
212184
end
213-
ensure
214-
ActiveRecord::QueryLogs.set_context(foo: nil)
215-
ActiveRecord::QueryLogs.tags = original_tags
216-
end
217-
218-
def test_set_context_restore_state
219-
original_tags = ActiveRecord::QueryLogs.tags
220-
ActiveRecord::QueryLogs.tags = [foo: ->(context) { context[:foo] }]
221-
ActiveRecord::QueryLogs.set_context(foo: "bar") do
222-
assert_sql(%r{/\*foo:bar\*/$}) { Dashboard.first }
223-
ActiveRecord::QueryLogs.set_context(foo: "plop") do
224-
assert_sql(%r{/\*foo:plop\*/$}) { Dashboard.first }
225-
end
226-
assert_sql(%r{/\*foo:bar\*/$}) { Dashboard.first }
227-
end
228-
ensure
229-
ActiveRecord::QueryLogs.tags = original_tags
230185
end
231186
end

0 commit comments

Comments
 (0)