Isolate retry span captures from global tracing registration

Merged
VA
4d ago
+142-5

The gRPC retry capture could observe zero or one attempt in a parallel suite while passing alone. A thread without a subscriber could register the shared RPC callsite while tracing-core's single-dispatcher optimization was active, caching it as disabled despite another thread owning a capture subscriber.

Both retry tests now retain a second dispatcher for their entire capture lifetime and run their assertions in isolated child processes. Captures remain per test and per future; no global subscriber or serialization is added. A deterministic regression registers the real unary RPC callsite without a subscriber before running the captured retry. Its negative control removes the second dispatcher and must lose both spans.

Decisions

  • Fix the test capture lifetime rather than alter RPC execution, tracing filters, retry behavior or assertions. The existing exact attempt and outcome assertions remain intact.
  • Exercise the real tracing dependency in a fresh child process to control its process-global first-registration state. The failing schedule is deterministic, not a stress run; the negative control must fail the specific two-span assertion with zero captured spans. No production synchronization or parser changes are made.
  • Isolate the original retry assertions too: another test may already be inside the single-dispatcher registration path when a capture starts. Thread-local dispatch alone cannot fence that in-flight global registration. The parent requires the child to report exactly one passing test; a successful empty test selection cannot pass validation. The concurrent test still interleaves its two independent captures inside that process.
  • The extra dispatcher is a test-local NoSubscriber instance. Keeping both live forces callsite registration to consider the registered capture instead of the unrelated registering thread's default subscriber. Each capture still owns a separate registry and collector.

Validation

  • Linux through bs.ps1: all 14 gRPC tests pass in 0.30 s (0.318 s process time), including both retry tests, the deterministic first-registration regression and its negative control. Build log: /home/var/log/buildbox/2026-10-16T093311918Z-3327150.log.
  • Windows lb.ps1 cargo check --locked -p acyclic-stream --features local,http --lib --tests passes in 7.23 s.

This isolates the span-capture failure found while validating #644. No latency threshold, connection invariant or retry assertion is weakened.


Summary by cubic

Fixes the gRPC retry span capture tests so they no longer observe zero or one attempt in a parallel suite. tracing-core's single-dispatcher fast path could cache the shared RPC callsite as disabled when a thread without a subscriber registered it first.

  • Both retry tests now run their assertions in isolated child processes and keep a second test-local dispatcher alive for the entire capture lifetime.
  • A deterministic regression registers the real unary RPC callsite without a subscriber before the captured retry; its negative control drops the second dispatcher and must fail with zero spans.
  • The concurrent retry test still runs its two independent captures in the same process, each with its own registry and collector.
  • No production code, retry behavior, or assertions changed; only the test capture infrastructure.