Skip to content

Commit 197726b

Browse files
committed
Shut down the OTel SDK between collector-mode specs
The collector-mode shared context boots a full OTel SDK per example via `start_agent` and never shut it down, leaking the batch span, periodic metric reader and batch log processor threads (~460 live threads by the end of a -collector CI run). The batch span thread was doubly stranded: the context swaps in an in-memory tracer provider for assertions, orphaning the booted one. Shut the booted tracer provider down before the swap, and shut the meter and logger providers down in an after hook. The after hook calls `Appsignal::OpenTelemetry.shutdown` directly rather than `Appsignal.stop`: stop's `Extension.stop` takes ~2 seconds per call, which across every collector-mode example adds minutes to the suite. [skip changeset]
1 parent bbb6aac commit 197726b

1 file changed

Lines changed: 17 additions & 3 deletions

File tree

spec/support/shared_contexts/collector_mode.rb

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,26 @@
1919

2020
before do
2121
start_agent(:options => { :collector_endpoint => "http://127.0.0.1:9090" })
22+
# `Appsignal.start` booted a full SDK tracer provider backed by a
23+
# BatchSpanProcessor (a background export thread). Shut it down before
24+
# swapping in the threadless in-memory provider: after the swap it is
25+
# unreachable and its thread would leak across examples.
26+
::OpenTelemetry.tracer_provider.shutdown
2227
::OpenTelemetry.tracer_provider = tracer_provider
2328
end
2429

25-
# `clear_current_transaction!` in spec_helper clears the thread-local but
26-
# not the attached OTel context. `complete_current!` does both.
27-
after { Appsignal::Transaction.complete_current! }
30+
after do
31+
# `clear_current_transaction!` in spec_helper clears the thread-local but
32+
# not the attached OTel context. `complete_current!` does both.
33+
Appsignal::Transaction.complete_current!
34+
# Shut the OTel SDK down so the meter and logger providers' background
35+
# threads don't accumulate across the suite. The targeted shutdown, not
36+
# `Appsignal.stop`: stop's `Extension.stop` takes ~2 seconds per call,
37+
# which across every collector-mode example adds minutes to the suite.
38+
# Runs before the global `Appsignal::OpenTelemetry.reset!` hook, so the
39+
# `started?` gate inside the shutdown still passes.
40+
Appsignal::OpenTelemetry.shutdown
41+
end
2842

2943
def root_span
3044
span_exporter.finished_spans.find { |s| [:server, :consumer].include?(s.kind) }

0 commit comments

Comments
 (0)