File tree Expand file tree Collapse file tree 3 files changed +58
-4
lines changed
lib/action_dispatch/middleware Expand file tree Collapse file tree 3 files changed +58
-4
lines changed Original file line number Diff line number Diff line change
1
+
2
+ * Add support for ` rack.response_finished ` callbacks in ActionDispatch::Executor.
3
+
4
+ The executor middleware now supports deferring completion callbacks to later
5
+ in the request lifecycle by utilizing Rack's ` rack.response_finished ` mechanism,
6
+ when available. This enables applications to define ` rack.response_finished ` callbacks
7
+ that may rely on state that would be cleaned up by the executor's completion callbacks.
8
+
9
+ * Adrianna Chang* , * Hartley McGuire*
10
+
1
11
* Add JSON support to the built-in health controller.
2
12
3
13
The health controller now responds to JSON requests with a structured response
Original file line number Diff line number Diff line change @@ -12,6 +12,10 @@ def initialize(app, executor)
12
12
13
13
def call ( env )
14
14
state = @executor . run! ( reset : true )
15
+ if response_finished = env [ "rack.response_finished" ]
16
+ response_finished << -> { state . complete! }
17
+ end
18
+
15
19
begin
16
20
response = @app . call ( env )
17
21
@@ -20,15 +24,21 @@ def call(env)
20
24
@executor . error_reporter . report ( error , handled : false , source : "application.action_dispatch" )
21
25
end
22
26
23
- returned = response << ::Rack ::BodyProxy . new ( response . pop ) { state . complete! }
27
+ unless response_finished
28
+ response << ::Rack ::BodyProxy . new ( response . pop ) { state . complete! }
29
+ end
30
+ returned = true
31
+ response
24
32
rescue Exception => error
25
33
request = ActionDispatch ::Request . new env
26
34
backtrace_cleaner = request . get_header ( "action_dispatch.backtrace_cleaner" )
27
35
wrapper = ExceptionWrapper . new ( backtrace_cleaner , error )
28
36
@executor . error_reporter . report ( wrapper . unwrapped_exception , handled : false , source : "application.action_dispatch" )
29
37
raise
30
38
ensure
31
- state . complete! unless returned
39
+ if !returned && !response_finished
40
+ state . complete!
41
+ end
32
42
end
33
43
end
34
44
end
Original file line number Diff line number Diff line change @@ -170,10 +170,44 @@ def test_handled_error_is_not_reported
170
170
end
171
171
end
172
172
173
+ def test_complete_callbacks_are_called_on_rack_response_finished
174
+ completed = false
175
+ executor . to_complete { completed = true }
176
+
177
+ env = { "rack.response_finished" => [ ] }
178
+ call_and_return_body ( env )
179
+
180
+ assert_not completed
181
+
182
+ assert_equal 1 , env [ "rack.response_finished" ] . size
183
+ env [ "rack.response_finished" ] . first . call
184
+
185
+ assert completed
186
+ end
187
+
188
+ def test_complete_callbacks_are_called_once_on_rack_response_finished_when_exception_is_raised
189
+ completed_count = 0
190
+ executor . to_complete { completed_count += 1 }
191
+
192
+ env = { "rack.response_finished" => [ ] }
193
+
194
+ begin
195
+ call_and_return_body ( env ) do
196
+ raise "error"
197
+ end
198
+ rescue
199
+ end
200
+
201
+ assert_equal 1 , env [ "rack.response_finished" ] . size
202
+ env [ "rack.response_finished" ] . first . call
203
+
204
+ assert_equal 1 , completed_count
205
+ end
206
+
173
207
private
174
- def call_and_return_body ( &block )
208
+ def call_and_return_body ( env = { } , &block )
175
209
app = block || proc { [ 200 , { } , [ ] ] }
176
- env = Rack ::MockRequest . env_for ( "" , { } )
210
+ env = Rack ::MockRequest . env_for ( "" , env )
177
211
_ , _ , body = middleware ( app ) . call ( env )
178
212
body
179
213
end
You can’t perform that action at this time.
0 commit comments