Skip to content

Commit 661b8e0

Browse files
authored
Supported nested Rack EventHandlers (#1101)
1 parent c76952f commit 661b8e0

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
bump: patch
3+
type: change
4+
---
5+
6+
Support apps that have multiple Appsignal::Rack::EventHandler-s in the middleware stack.

lib/appsignal/rack/event_handler.rb

+21
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
module Appsignal
44
module Rack
55
APPSIGNAL_TRANSACTION = "appsignal.transaction"
6+
APPSIGNAL_EVENT_HANDLER_ID = "appsignal.event_handler_id"
67
RACK_AFTER_REPLY = "rack.after_reply"
78

89
class EventHandler
@@ -16,8 +17,22 @@ def self.safe_execution(name)
1617
)
1718
end
1819

20+
attr_reader :id
21+
22+
def initialize
23+
@id = SecureRandom.uuid
24+
end
25+
26+
def request_handler?(given_id)
27+
id == given_id
28+
end
29+
1930
def on_start(request, _response)
31+
event_handler = self
2032
self.class.safe_execution("Appsignal::Rack::EventHandler#on_start") do
33+
request.env[APPSIGNAL_EVENT_HANDLER_ID] ||= id
34+
return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
35+
2136
transaction = Appsignal::Transaction.create(
2237
SecureRandom.uuid,
2338
Appsignal::Transaction::HTTP_REQUEST,
@@ -29,6 +44,8 @@ def on_start(request, _response)
2944
request.env[RACK_AFTER_REPLY] << proc do
3045
Appsignal::Rack::EventHandler
3146
.safe_execution("Appsignal::Rack::EventHandler's after_reply") do
47+
next unless event_handler.request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
48+
3249
transaction.finish_event("process_request.rack", "", "")
3350
transaction.set_http_or_background_queue_start
3451

@@ -48,6 +65,8 @@ def on_start(request, _response)
4865

4966
def on_error(request, _response, error)
5067
self.class.safe_execution("Appsignal::Rack::EventHandler#on_error") do
68+
return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
69+
5170
transaction = request.env[APPSIGNAL_TRANSACTION]
5271
return unless transaction
5372

@@ -57,6 +76,8 @@ def on_error(request, _response, error)
5776

5877
def on_finish(request, response)
5978
self.class.safe_execution("Appsignal::Rack::EventHandler#on_finish") do
79+
return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
80+
6081
transaction = request.env[APPSIGNAL_TRANSACTION]
6182
return unless transaction
6283

spec/lib/appsignal/rack/event_handler_spec.rb

+37-3
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111
let(:response) { nil }
1212
let(:log_stream) { StringIO.new }
1313
let(:log) { log_contents(log_stream) }
14+
let(:event_handler_instance) { described_class.new }
1415
before do
1516
start_agent
1617
Appsignal.internal_logger = test_logger(log_stream)
1718
end
1819
around { |example| keep_transactions { example.run } }
1920

2021
def on_start
21-
described_class.new.on_start(request, response)
22+
event_handler_instance.on_start(request, response)
2223
end
2324

2425
describe "#on_start" do
@@ -34,6 +35,14 @@ def on_start
3435
expect(Appsignal::Transaction.current).to eq(last_transaction)
3536
end
3637

38+
context "when the handler is nested in another EventHandler" do
39+
it "does not create a new transaction in the nested EventHandler" do
40+
on_start
41+
expect { described_class.new.on_start(request, response) }
42+
.to_not(change { created_transactions.length })
43+
end
44+
end
45+
3746
it "registers transaction on the request environment" do
3847
on_start
3948

@@ -87,7 +96,7 @@ def on_start
8796

8897
describe "#on_error" do
8998
def on_error(error)
90-
described_class.new.on_error(request, response, error)
99+
event_handler_instance.on_error(request, response, error)
91100
end
92101

93102
it "reports the error" do
@@ -103,6 +112,15 @@ def on_error(error)
103112
)
104113
end
105114

115+
context "when the handler is nested in another EventHandler" do
116+
it "does not report the error on the transaction" do
117+
on_start
118+
described_class.new.on_error(request, response, ExampleStandardError.new("the error"))
119+
120+
expect(last_transaction.to_h).to include("error" => nil)
121+
end
122+
end
123+
106124
it "logs an error in case of an internal error" do
107125
on_start
108126

@@ -122,7 +140,7 @@ def on_error(error)
122140
let(:response) { Rack::Events::BufferedResponse.new(200, {}, ["body"]) }
123141

124142
def on_finish
125-
described_class.new.on_finish(request, response)
143+
event_handler_instance.on_finish(request, response)
126144
end
127145

128146
it "doesn't do anything without a transaction" do
@@ -155,6 +173,22 @@ def on_finish
155173
)
156174
)
157175
expect(last_transaction.ext.queue_start).to eq(queue_start_time)
176+
expect(last_transaction).to be_completed
177+
end
178+
179+
context "when the handler is nested in another EventHandler" do
180+
it "does not complete the transaction" do
181+
on_start
182+
described_class.new.on_finish(request, response)
183+
184+
expect(last_transaction.to_h).to include(
185+
"action" => nil,
186+
"metadata" => {},
187+
"sample_data" => {},
188+
"events" => []
189+
)
190+
expect(last_transaction).to_not be_completed
191+
end
158192
end
159193

160194
it "doesn't set the action name if already set" do

0 commit comments

Comments
 (0)