Skip to content

Commit 4058a91

Browse files
fix(context): do not modify stack array directly when attach and detach
1 parent 555b062 commit 4058a91

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

api/lib/opentelemetry/context.rb

+4-3
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ def current
4141
# @return [Object] A token to be used when detaching
4242
def attach(context)
4343
s = stack
44-
s.push(context)
45-
s.size
44+
new_stack = s + [context]
45+
Thread.current[STACK_KEY] = new_stack
46+
new_stack.size
4647
end
4748

4849
# Restores the previous Context associated with the current Fiber.
@@ -57,7 +58,7 @@ def detach(token)
5758
calls_matched = (token == s.size)
5859
OpenTelemetry.handle_error(exception: DetachError.new('calls to detach should match corresponding calls to attach.')) unless calls_matched
5960

60-
s.pop
61+
Thread.current[STACK_KEY] = s[...-1] || []
6162
calls_matched
6263
end
6364

api/test/opentelemetry/context_test.rb

+55
Original file line numberDiff line numberDiff line change
@@ -331,5 +331,60 @@
331331
_(Context.current[bar_key]).must_be_nil
332332
end
333333
end
334+
335+
describe 'when current thread local variable get copied to new thread' do
336+
# NOTE: this is the similar behavior of ActionController::Live as identified in open-telemetry/opentelemetry-ruby-contrib#772
337+
it 'attach and detach in child thread will not affect parent thread' do
338+
OpenTelemetry::TestHelpers.with_test_logger do |log_stream|
339+
ctx = new_context
340+
341+
t1 = Thread.current
342+
locals = t1.keys.map { |key| [key, t1[key]] }
343+
344+
done_attach_new_context = false
345+
346+
token1 = Context.attach(ctx)
347+
Thread.new do
348+
t2 = Thread.current
349+
locals.each { |k, v| t2[k] = v }
350+
351+
Context.attach(ctx)
352+
done_attach_new_context = true
353+
end
354+
355+
until done_attach_new_context; end
356+
357+
Context.detach(token1)
358+
359+
_(log_stream.string).wont_match(/OpenTelemetry error: calls to detach should match corresponding calls to attach/)
360+
end
361+
end
362+
363+
it 'clear in child thread will not affect parent thread' do
364+
OpenTelemetry::TestHelpers.with_test_logger do |log_stream|
365+
ctx = new_context
366+
367+
t1 = Thread.current
368+
locals = t1.keys.map { |key| [key, t1[key]] }
369+
370+
done_clear_context = false
371+
372+
token1 = Context.attach(ctx)
373+
Thread.new do
374+
t2 = Thread.current
375+
locals.each { |k, v| t2[k] = v }
376+
377+
Context.clear
378+
done_clear_context = true
379+
end
380+
381+
until done_clear_context; end
382+
383+
Context.detach(token1)
384+
385+
_(log_stream.string).wont_match(/OpenTelemetry error: calls to detach should match corresponding calls to attach/)
386+
end
387+
end
388+
end
334389
end
335390
end

0 commit comments

Comments
 (0)