after_response 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|