Skip to content

Commit 084a92a

Browse files
committed
Changed: Only apply Rails #initialize hooks once per app.
1 parent 5b6bfe1 commit 084a92a

File tree

2 files changed

+47
-12
lines changed

2 files changed

+47
-12
lines changed

lib/ddtrace/contrib/rails/patcher.rb

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ def patch_before_intialize
3232
end
3333

3434
def before_intialize(app)
35-
# Middleware must be added before the application is initialized.
36-
# Otherwise the middleware stack will be frozen.
37-
# Sometimes we don't want to activate middleware e.g. OpenTracing, etc.
38-
add_middleware(app) if Datadog.configuration[:rails][:middleware]
35+
do_once(:rails_before_initialize, for: app) do
36+
# Middleware must be added before the application is initialized.
37+
# Otherwise the middleware stack will be frozen.
38+
# Sometimes we don't want to activate middleware e.g. OpenTracing, etc.
39+
add_middleware(app) if Datadog.configuration[:rails][:middleware]
40+
end
3941
end
4042

4143
def add_middleware(app)
@@ -59,10 +61,12 @@ def patch_after_intialize
5961
end
6062

6163
def after_intialize(app)
62-
# Finish configuring the tracer after the application is initialized.
63-
# We need to wait for some things, like application name, middleware stack, etc.
64-
setup_tracer
65-
instrument_rails
64+
do_once(:rails_after_initialize, for: app) do
65+
# Finish configuring the tracer after the application is initialized.
66+
# We need to wait for some things, like application name, middleware stack, etc.
67+
setup_tracer
68+
instrument_rails
69+
end
6670
end
6771

6872
# Configure Rails tracing with settings

spec/ddtrace/contrib/rails/railtie_spec.rb

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ def index
2222

2323
RSpec::Matchers.define :have_kind_of_middleware do |expected|
2424
match do |actual|
25+
found = 0
2526
while actual
26-
return true if actual.class <= expected
27+
found += 1 if actual.class <= expected
2728
without_warnings { actual = actual.instance_variable_get(:@app) }
2829
end
29-
false
30+
found == (count || 1)
3031
end
32+
33+
chain :once do
34+
@count = 1
35+
end
36+
37+
chain :copies, :count
3138
end
3239

3340
before(:each) do
@@ -44,8 +51,8 @@ def index
4451
context 'set to true' do
4552
let(:rails_options) { super().merge(middleware: true) }
4653

47-
it { expect(app).to have_kind_of_middleware(Datadog::Contrib::Rack::TraceMiddleware) }
48-
it { expect(app).to have_kind_of_middleware(Datadog::Contrib::Rails::ExceptionMiddleware) }
54+
it { expect(app).to have_kind_of_middleware(Datadog::Contrib::Rack::TraceMiddleware).once }
55+
it { expect(app).to have_kind_of_middleware(Datadog::Contrib::Rails::ExceptionMiddleware).once }
4956
end
5057

5158
context 'set to false' do
@@ -56,4 +63,28 @@ def index
5663
it { expect(app).to_not have_kind_of_middleware(Datadog::Contrib::Rails::ExceptionMiddleware) }
5764
end
5865
end
66+
67+
describe 'when load hooks run twice' do
68+
before(:each) do
69+
# Set expectations
70+
expect(Datadog::Contrib::Rails::Patcher).to receive(:add_middleware)
71+
.with(a_kind_of(Rails::Application))
72+
.once
73+
.and_call_original
74+
75+
without_warnings do
76+
# Then load the app, which run load hooks
77+
app
78+
79+
# Then manually re-run load hooks
80+
ActiveSupport.run_load_hooks(:before_initialize, app)
81+
ActiveSupport.run_load_hooks(:after_initialize, app)
82+
end
83+
end
84+
85+
it 'only includes the middleware once' do
86+
expect(app).to have_kind_of_middleware(Datadog::Contrib::Rack::TraceMiddleware).once
87+
expect(app).to have_kind_of_middleware(Datadog::Contrib::Rails::ExceptionMiddleware).once
88+
end
89+
end
5990
end

0 commit comments

Comments
 (0)