after_response 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/after_response.gemspec +2 -2
- data/lib/after_response.rb +10 -0
- data/lib/after_response/adapters/passenger2_2.rb +72 -0
- data/lib/after_response/adapters/passenger3.rb +11 -0
- data/lib/after_response/adapters/unicorn_middleware.rb +33 -0
- data/lib/after_response/adapters/unicorn_monkeypatch.rb +9 -0
- data/lib/after_response/callbacks.rb +80 -0
- metadata +11 -6
data/after_response.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "after_response"
|
3
|
-
s.version = "0.9.
|
3
|
+
s.version = "0.9.3"
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.summary = "Provides hooks to execute callbacks after the response has been delivered to the client."
|
6
6
|
|
@@ -11,7 +11,7 @@ the response to the client application sooner. This would mainly include logging
|
|
11
11
|
event logging service, sending email and other tasks that do not affect the response body in any way.
|
12
12
|
EOF
|
13
13
|
|
14
|
-
s.files = Dir['{lib
|
14
|
+
s.files = Dir['{lib/**/*,rails/**/*}'] +
|
15
15
|
%w(after_response.gemspec CHANGELOG README)
|
16
16
|
s.require_path = 'lib'
|
17
17
|
s.extra_rdoc_files = ['README', 'CHANGELOG']
|
data/lib/after_response.rb
CHANGED
@@ -57,6 +57,16 @@ module AfterResponse
|
|
57
57
|
@after_response_attached
|
58
58
|
end
|
59
59
|
|
60
|
+
# If a container adapter isn't available, this method can be called to enable the buffering of events,
|
61
|
+
# and Starboard::EventQueue.flush! must be called manually
|
62
|
+
def self.buffer_and_flush_manually!
|
63
|
+
@after_response_attached ||= begin
|
64
|
+
raise "Callback hook already installed for #{current_container.name}" if current_container
|
65
|
+
logger.info{ "[AfterResponse] => Will flush manually" }
|
66
|
+
true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
60
70
|
def self.logger
|
61
71
|
@logger ||= begin
|
62
72
|
if defined?(Rails)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# ACK... Passenger < 3.0 sucks because request loop can't be wrapped to do what we need.
|
2
|
+
# https://github.com/FooBarWidget/passenger/blob/release-2.2.14/lib/phusion_passenger/abstract_request_handler.rb
|
3
|
+
# We have to overwrite the entire AbstractRequestHandler#main_loop method. Here goes.
|
4
|
+
|
5
|
+
class PhusionPassenger::AbstractRequestHandler
|
6
|
+
# Enter the request handler's main loop.
|
7
|
+
def main_loop
|
8
|
+
reset_signal_handlers
|
9
|
+
begin
|
10
|
+
@graceful_termination_pipe = IO.pipe
|
11
|
+
@graceful_termination_pipe[0].close_on_exec!
|
12
|
+
@graceful_termination_pipe[1].close_on_exec!
|
13
|
+
|
14
|
+
@main_loop_thread_lock.synchronize do
|
15
|
+
@main_loop_generation += 1
|
16
|
+
@main_loop_running = true
|
17
|
+
@main_loop_thread_cond.broadcast
|
18
|
+
end
|
19
|
+
|
20
|
+
install_useful_signal_handlers
|
21
|
+
|
22
|
+
while true
|
23
|
+
@iterations += 1
|
24
|
+
client = accept_connection
|
25
|
+
if client.nil?
|
26
|
+
break
|
27
|
+
end
|
28
|
+
begin
|
29
|
+
headers, input = parse_request(client)
|
30
|
+
if headers
|
31
|
+
if headers[REQUEST_METHOD] == PING
|
32
|
+
process_ping(headers, input, client)
|
33
|
+
else
|
34
|
+
process_request(headers, input, client)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
rescue IOError, SocketError, SystemCallError => e
|
38
|
+
print_exception("Passenger RequestHandler", e)
|
39
|
+
ensure
|
40
|
+
# 'input' is the same as 'client' so we don't
|
41
|
+
# need to close that.
|
42
|
+
# The 'close_write' here prevents forked child
|
43
|
+
# processes from unintentionally keeping the
|
44
|
+
# connection open.
|
45
|
+
client.close_write rescue nil
|
46
|
+
client.close rescue nil
|
47
|
+
# All this crap to add one line...
|
48
|
+
AfterResponse::Callbacks.perform_after_response_callbacks!
|
49
|
+
end
|
50
|
+
@processed_requests += 1
|
51
|
+
end
|
52
|
+
rescue EOFError
|
53
|
+
# Exit main loop.
|
54
|
+
rescue Interrupt
|
55
|
+
# Exit main loop.
|
56
|
+
rescue SignalException => signal
|
57
|
+
if signal.message != HARD_TERMINATION_SIGNAL &&
|
58
|
+
signal.message != SOFT_TERMINATION_SIGNAL
|
59
|
+
raise
|
60
|
+
end
|
61
|
+
ensure
|
62
|
+
revert_signal_handlers
|
63
|
+
@main_loop_thread_lock.synchronize do
|
64
|
+
@graceful_termination_pipe[0].close rescue nil
|
65
|
+
@graceful_termination_pipe[1].close rescue nil
|
66
|
+
@main_loop_generation += 1
|
67
|
+
@main_loop_running = false
|
68
|
+
@main_loop_thread_cond.broadcast
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class PhusionPassenger::AbstractRequestHandler
|
2
|
+
|
3
|
+
protected
|
4
|
+
def accept_and_process_next_request_with_after_response(*args)
|
5
|
+
returning(accept_and_process_next_request_without_after_response(*args)) do
|
6
|
+
AfterResponse::Callbacks.perform_after_response_callbacks!
|
7
|
+
end
|
8
|
+
end
|
9
|
+
alias_method_chain :accept_and_process_next_request, :after_response
|
10
|
+
|
11
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module AfterResponse
|
2
|
+
|
3
|
+
module Adapters
|
4
|
+
#
|
5
|
+
# Example (in config.ru):
|
6
|
+
#
|
7
|
+
# require 'after_response/adapters/unicorn'
|
8
|
+
#
|
9
|
+
# use AfterResponse::Adapters::UnicornMiddleware
|
10
|
+
class UnicornMiddleware < Struct.new(:app, :body)
|
11
|
+
|
12
|
+
def initialize(app)
|
13
|
+
super(app)
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
status, headers, self.body = app.call(env)
|
18
|
+
[ status, headers, self ]
|
19
|
+
end
|
20
|
+
|
21
|
+
def each(&block)
|
22
|
+
body.each(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
# In Unicorn, this is called _after_ the socket is closed. (Not true for at least passenger3)
|
26
|
+
def close
|
27
|
+
body.close if body.respond_to?(:close)
|
28
|
+
AfterResponse::Callbacks.perform_after_response_callbacks!
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Unicorn::HttpServer
|
2
|
+
alias process_client_without_after_response process_client
|
3
|
+
undef_method :process_client
|
4
|
+
def process_client(client)
|
5
|
+
result = process_client_without_after_response(client)
|
6
|
+
AfterResponse::Callbacks.perform_after_response_callbacks!
|
7
|
+
result
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module AfterResponse
|
2
|
+
|
3
|
+
def self.callbacks
|
4
|
+
Callbacks.callbacks
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.transient_callbacks
|
8
|
+
Callbacks.transient_callbacks
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.append_after_response(&block)
|
12
|
+
Callbacks.append_after_response(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.append_transient_after_response(&block)
|
16
|
+
Callbacks.append_transient_after_response(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
module Callbacks
|
20
|
+
|
21
|
+
module Helpers
|
22
|
+
def self.included(mod)
|
23
|
+
mod.send(:include, TransientHelpers)
|
24
|
+
mod.send(:extend, ModuleHelpers)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# ApplicationController should include this
|
29
|
+
module TransientHelpers
|
30
|
+
def after_response(&block)
|
31
|
+
AfterResponse.append_transient_after_response(&block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# ApplicationController should extend this
|
36
|
+
module ModuleHelpers
|
37
|
+
def after_response(&block)
|
38
|
+
AfterResponse.append_after_response(&block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.append_after_response(&block)
|
43
|
+
if AfterResponse.bufferable?
|
44
|
+
callbacks << block
|
45
|
+
else
|
46
|
+
block.call
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.append_transient_after_response(&block)
|
51
|
+
if AfterResponse.bufferable?
|
52
|
+
transient_callbacks << block
|
53
|
+
else
|
54
|
+
block.call
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.callbacks
|
59
|
+
Thread.current[:__after_response_callbacks__] ||= []
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.transient_callbacks
|
63
|
+
Thread.current[:__transient_after_response_callbacks__] ||= []
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.all_callbacks
|
67
|
+
transient_callbacks + callbacks
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.perform_after_response_callbacks!
|
71
|
+
all_callbacks.each do |b|
|
72
|
+
b.call
|
73
|
+
end
|
74
|
+
ensure
|
75
|
+
AfterResponse.transient_callbacks.clear
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: after_response
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 61
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
version: 0.9.
|
9
|
+
- 3
|
10
|
+
version: 0.9.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kevin E. Hunt
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-05-02 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -34,6 +34,11 @@ extra_rdoc_files:
|
|
34
34
|
- README
|
35
35
|
- CHANGELOG
|
36
36
|
files:
|
37
|
+
- lib/after_response/adapters/passenger2_2.rb
|
38
|
+
- lib/after_response/adapters/passenger3.rb
|
39
|
+
- lib/after_response/adapters/unicorn_middleware.rb
|
40
|
+
- lib/after_response/adapters/unicorn_monkeypatch.rb
|
41
|
+
- lib/after_response/callbacks.rb
|
37
42
|
- lib/after_response.rb
|
38
43
|
- rails/init.rb
|
39
44
|
- after_response.gemspec
|
@@ -69,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
74
|
requirements: []
|
70
75
|
|
71
76
|
rubyforge_project:
|
72
|
-
rubygems_version: 1.
|
77
|
+
rubygems_version: 1.5.2
|
73
78
|
signing_key:
|
74
79
|
specification_version: 3
|
75
80
|
summary: Provides hooks to execute callbacks after the response has been delivered to the client.
|