Skip to content

Commit 387e6bf

Browse files
ClearEventReporterContext handles case where rack.response_finished is not supported
1 parent 906ab94 commit 387e6bf

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

actionpack/lib/action_dispatch/middleware/clear_event_reporter_context.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22

33
module ActionDispatch
4+
# TODO: This should go away if we ship https://github.com/rails/rails/pull/55425
5+
#
46
# Middleware that sets up a callback on rack.response_finished to clear
57
# the EventReporter context when the response is finished. This ensures that
68
# context is cleared as late as possible in the request lifecycle.
@@ -10,11 +12,18 @@ def initialize(app)
1012
end
1113

1214
def call(env)
15+
if response_finished = env["rack.response_finished"]
16+
response_finished << -> do
17+
ActiveSupport.event_reporter.clear_context
18+
end
19+
end
20+
1321
response = @app.call(env)
1422

15-
env["rack.response_finished"] ||= []
16-
env["rack.response_finished"] << -> do
17-
ActiveSupport.event_reporter.clear_context
23+
unless response_finished
24+
response << ::Rack::BodyProxy.new(response.pop) do
25+
ActiveSupport.event_reporter.clear_context
26+
end
1827
end
1928

2029
response

actionpack/test/dispatch/clear_event_reporter_context_test.rb

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
class ClearEventReporterContextTest < ActiveSupport::TestCase
66
def setup
77
@app = ->(env) { [200, {}, ["Hello"]] }
8-
@middleware = ActionDispatch::ClearEventReporterContext.new(@app)
98
@reporter = ActiveSupport.event_reporter
109
end
1110

1211
test "clears event reporter context in response finished callback" do
1312
@reporter.set_context(shop_id: 123)
1413

15-
env = {}
16-
@middleware.call(env)
14+
env = Rack::MockRequest.env_for("", { "rack.response_finished" => [] })
15+
middleware(@app).call(env)
1716

1817
assert env["rack.response_finished"]
1918
assert_equal 1, env["rack.response_finished"].length
@@ -23,17 +22,46 @@ def setup
2322
assert_equal({}, @reporter.context)
2423
end
2524

26-
test "clears event reporter context when exception is raised" do
25+
test "clears event reporter context via Rack::BodyProxy when rack.response_finished is not supported" do
2726
@reporter.set_context(shop_id: 123)
2827

28+
env = Rack::MockRequest.env_for("", {})
29+
response = middleware(@app).call(env)
30+
31+
assert_equal({ shop_id: 123 }, @reporter.context)
32+
33+
body = response[2]
34+
body.close
35+
36+
assert_equal({}, @reporter.context)
37+
end
38+
39+
test "clears event reporter context via rack.response_finished when exception is raised" do
40+
@reporter.set_context(shop_id: 123)
41+
42+
env = Rack::MockRequest.env_for("", { "rack.response_finished" => [] })
2943
exception_app = ->(env) { raise StandardError, "Test exception" }
30-
exception_middleware = ActionDispatch::ClearEventReporterContext.new(exception_app)
44+
assert_raises(StandardError) do
45+
middleware(exception_app).call(env)
46+
end
3147

32-
env = {}
48+
assert_equal({}, @reporter.context)
49+
end
50+
51+
test "clears event reporter context when exception is raised and rack.response_finished is not supported" do
52+
@reporter.set_context(shop_id: 123)
53+
54+
exception_app = ->(env) { raise StandardError, "Test exception" }
55+
env = Rack::MockRequest.env_for("", {}) # Add missing env variable
3356
assert_raises(StandardError) do
34-
exception_middleware.call(env)
57+
middleware(exception_app).call(env)
3558
end
3659

3760
assert_equal({}, @reporter.context)
3861
end
62+
63+
private
64+
def middleware(inner_app)
65+
Rack::Lint.new(ActionDispatch::ClearEventReporterContext.new(Rack::Lint.new(inner_app)))
66+
end
3967
end

0 commit comments

Comments
 (0)