Summary
While working on #3380 (fix for #2802), I noticed that the existing test suite for BatchSpanProcessor, BatchLogProcessor, and PeriodicReader has significant coverage gaps around tokio runtime interactions. The deadlock bug in #2802 went undetected because no tests exercise exporters that depend on tokio internals.
Status (2026-05-09)
#3380 has since expanded test coverage to address most of the items below. The TokioSpawn*Exporter mocks now exercise both the timer and IO drivers; coverage spans multi_thread(1), multi_thread(default workers), current_thread, and empty-buffer scenarios for force_flush, shutdown, and shutdown_with_timeout across all three processors. Still open: gap 4 (un-ignore the SimpleLogProcessor async exporter tests) and gap 5 (integration tests against a real exporter / mock OTLP collector). The checklist at the bottom has per-item status.
Gaps identified
1. All runtime-flavor tests use simple exporters
The existing #[tokio::test(flavor = "current_thread")] and #[tokio::test(flavor = "multi_thread", worker_threads = 1)] tests use MockSpanExporter, InMemoryLogExporter, and InMemoryMetricExporter — none of which call tokio::spawn, use tokio I/O, or otherwise depend on the tokio runtime context. These tests pass regardless of whether the runtime context is available on the processor's worker thread, so they cannot catch deadlocks like #2802.
PR #3380 adds initial regression tests with TokioSpawn*Exporter mocks for multi_thread(1), but coverage is still limited.
2. No shutdown() tests with tokio-dependent exporters
The original issue (#2802, reproduction in #3356 (comment)) documented deadlocks on both force_flush() and shutdown(). The regression tests in #3380 only cover force_flush(). The shutdown() path goes through similar code but has different timeout behavior (5s timeout vs. infinite hang) that should be verified.
3. No timeout or cancellation tests
force_flush() on current_thread runtime with tonic-like exporters hangs forever (recv() has no timeout)
shutdown() returns Err(Timeout(5s)) but the worker thread stays stuck
- These scenarios aren't tested or documented
4. SimpleLogProcessor has ignored async exporter tests
Two tests in simple_log_processor are #[ignore]d:
test_simple_processor_async_exporter_with_all_runtime_worker_threads_blocked
test_simple_processor_async_exporter_with_current_thread_runtime
These suggest known but unaddressed issues with async exporters on constrained runtimes in the simple processor path.
5. No integration tests with real exporters
All processor tests use in-memory or mock exporters. There are no integration tests that exercise the actual OTLP/tonic export path against a mock collector, which is where deadlocks manifest in practice.
Suggested improvements
Context
Summary
While working on #3380 (fix for #2802), I noticed that the existing test suite for
BatchSpanProcessor,BatchLogProcessor, andPeriodicReaderhas significant coverage gaps around tokio runtime interactions. The deadlock bug in #2802 went undetected because no tests exercise exporters that depend on tokio internals.Status (2026-05-09)
#3380 has since expanded test coverage to address most of the items below. The
TokioSpawn*Exportermocks now exercise both the timer and IO drivers; coverage spansmulti_thread(1),multi_thread(default workers),current_thread, and empty-buffer scenarios forforce_flush,shutdown, andshutdown_with_timeoutacross all three processors. Still open: gap 4 (un-ignore theSimpleLogProcessorasync exporter tests) and gap 5 (integration tests against a real exporter / mock OTLP collector). The checklist at the bottom has per-item status.Gaps identified
1. All runtime-flavor tests use simple exporters
The existing
#[tokio::test(flavor = "current_thread")]and#[tokio::test(flavor = "multi_thread", worker_threads = 1)]tests useMockSpanExporter,InMemoryLogExporter, andInMemoryMetricExporter— none of which calltokio::spawn, use tokio I/O, or otherwise depend on the tokio runtime context. These tests pass regardless of whether the runtime context is available on the processor's worker thread, so they cannot catch deadlocks like #2802.PR #3380 adds initial regression tests with
TokioSpawn*Exportermocks formulti_thread(1), but coverage is still limited.2. No
shutdown()tests with tokio-dependent exportersThe original issue (#2802, reproduction in #3356 (comment)) documented deadlocks on both
force_flush()andshutdown(). The regression tests in #3380 only coverforce_flush(). Theshutdown()path goes through similar code but has different timeout behavior (5s timeout vs. infinite hang) that should be verified.3. No timeout or cancellation tests
force_flush()oncurrent_threadruntime with tonic-like exporters hangs forever (recv()has no timeout)shutdown()returnsErr(Timeout(5s))but the worker thread stays stuck4.
SimpleLogProcessorhas ignored async exporter testsTwo tests in
simple_log_processorare#[ignore]d:test_simple_processor_async_exporter_with_all_runtime_worker_threads_blockedtest_simple_processor_async_exporter_with_current_thread_runtimeThese suggest known but unaddressed issues with async exporters on constrained runtimes in the simple processor path.
5. No integration tests with real exporters
All processor tests use in-memory or mock exporters. There are no integration tests that exercise the actual OTLP/tonic export path against a mock collector, which is where deadlocks manifest in practice.
Suggested improvements
shutdown()regression tests withTokioSpawn*Exportermocks for all three processors (fix(sdk): resolve exporter deadlock on constrained tokio runtimes #3380)shutdown_with_timeoutcovered for span/log/metric in fix(sdk): resolve exporter deadlock on constrained tokio runtimes #3380 viacurrent_thread+TokioSpawn*Exporterregression tests.force_flushhas no timeout, so a hang there is genuine and isn't asserted.SimpleLogProcessorasync exporter testscurrent_threadruntime limitation — inline test comments in fix(sdk): resolve exporter deadlock on constrained tokio runtimes #3380 now describe it; broader user-facing docs (crate-level / book) still TBD.Context