Skip to content

Commit 1acdf59

Browse files
Merge pull request #4779 from DataDog/fix-rack
Rack: Ensure proxy span always finishes Co-authored-by: marcotc <[email protected]>
2 parents 857a87a + 964e4ed commit 1acdf59

File tree

3 files changed

+26
-15
lines changed

3 files changed

+26
-15
lines changed

lib/datadog/tracing/contrib/rack/request_queue.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def get_request_start(env, now = Core::Utils::Time.now.utc)
2424
# nginx header is seconds in the format "t=1512379167.574"
2525
# apache header is microseconds in the format "t=1570633834463123"
2626
# heroku header is milliseconds in the format "1570634024294"
27+
# @see https://github.com/heroku/vegur/blob/65d168f757e0ddb448f41cfb9e4b0281c747378d/README.md?plain=1#L383-L384
2728
time_string = header.to_s.delete('^0-9')
2829
return if time_string.nil?
2930

lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ def call(env, configuration)
4343
# excluding the time spent processing the request itself
4444
queue_span.finish
4545

46-
yield.tap { request_span.finish }
46+
yield
47+
ensure
48+
# Ensure that the spans are finished even if an exception is raised.
49+
# **This is very important** to prevent the trace from leaking between requests,
50+
# especially because `queue_span` is normally a root span.
51+
queue_span&.finish
52+
request_span&.finish
4753
end
4854
end
4955
end

spec/datadog/tracing/contrib/rack/trace_proxy_middleware_spec.rb

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
RSpec.describe Datadog::Tracing::Contrib::Rack::TraceProxyMiddleware do
66
describe '#call' do
77
let(:service) { 'nginx' }
8+
let(:env) { { 'HTTP_X_REQUEST_START' => timestamp.to_i * 1000 } }
89

910
context 'when given timestamp' do
10-
let(:timestamp) { Time.now.utc }
11+
let(:timestamp) { Time.at(1757000000) }
1112

1213
context 'when request_queuing: true' do
1314
it 'behaves like request_queuing: :exclude_request' do
14-
env = double
15-
expect(Datadog::Tracing::Contrib::Rack::QueueTime).to receive(:get_request_start).with(env).and_return(timestamp)
16-
1715
result = described_class.call(env, request_queuing: true, web_service_name: service) { :success }
1816

1917
expect(result).to eq :success
@@ -41,13 +39,25 @@
4139
expect(queue_span.get_tag('span.kind')).to eq('proxy')
4240
expect(queue_span).to be_measured
4341
end
42+
43+
context 'when the request fails' do
44+
it 'finishes the spans even if an exception is raised' do
45+
expect do
46+
described_class.call(env, request_queuing: true, web_service_name: service) { raise 'error' }
47+
end.to raise_error('error')
48+
49+
expect(spans).to have(2).items
50+
queue_span, request_span = spans
51+
expect(request_span).to be_root_span
52+
expect(queue_span.parent_id).to eq(request_span.id)
53+
expect(request_span).to be_finished
54+
expect(queue_span).to be_finished
55+
end
56+
end
4457
end
4558

4659
context 'when request_queuing: false' do
4760
it 'does not create spans' do
48-
env = double
49-
allow(Datadog::Tracing::Contrib::Rack::QueueTime).to receive(:get_request_start).with(env).and_return(timestamp)
50-
5161
result = described_class.call(env, request_queuing: false, web_service_name: service) { :success }
5262

5363
expect(result).to eq :success
@@ -57,14 +67,11 @@
5767
end
5868
end
5969

60-
context 'when given withouht timestamp' do
70+
context 'when given without timestamp' do
6171
let(:timestamp) { nil }
6272

6373
context 'when request_queuing: true' do
6474
it 'does not create spans' do
65-
env = double
66-
expect(Datadog::Tracing::Contrib::Rack::QueueTime).to receive(:get_request_start).with(env).and_return(timestamp)
67-
6875
result = described_class.call(env, request_queuing: true, web_service_name: service) { :success }
6976

7077
expect(result).to eq :success
@@ -75,9 +82,6 @@
7582

7683
context 'when request_queuing: false' do
7784
it 'does not create spans' do
78-
env = double
79-
allow(Datadog::Tracing::Contrib::Rack::QueueTime).to receive(:get_request_start).with(env).and_return(timestamp)
80-
8185
result = described_class.call(env, request_queuing: false, web_service_name: service) { :success }
8286

8387
expect(result).to eq :success

0 commit comments

Comments
 (0)