Skip to content

fix(plugin): async shutdown hook returns forceFlush Promise + drop sdk.shutdown bus race#78

Merged
Alezander9 merged 1 commit into
mainfrom
alex/v4-async-shutdown-drain
May 17, 2026
Merged

fix(plugin): async shutdown hook returns forceFlush Promise + drop sdk.shutdown bus race#78
Alezander9 merged 1 commit into
mainfrom
alex/v4-async-shutdown-drain

Conversation

@Alezander9
Copy link
Copy Markdown
Member

@Alezander9 Alezander9 commented May 17, 2026

rc3 diagnostic captured two compounding bugs.**1.** bcode-laminar's server.instance.disposedbus handler awaitssdk.shutdown(), which unregisters the global TracerProvider AND closes the BatchSpanProcessor. In headless bcode runmode this fires before the top-levelfinally, so by the time the sync shutdown hook runs, the provider is gone and the BSP queue is dropped. Diagnostic: [bcode-laminar] shutdown invoked: ending 0 turn span(s).2. The top-level finally fell back to trace.getTracerProvider().forceFlush(), but the OTel API's ProxyTracerProvider does not expose forceFlush — so even when the global was still registered the fallback was a no-op. Diagnostic: [bcode] shutdown: no forceFlush on global provider.**Fix.**``- Hooks.shutdownreturn type widened tovoid | Promise so plugins can return a Promise the host awaits.- bcode-laminar.shutdown now ends any still-open turn spans then returns processor.forceFlush() directly. The closure ref to processor bypasses the broken global lookup entirely.- Drop await sdk.shutdown()fromserver.instance.disposed (the handler now just ends remaining spans).- src/index.ts: drop the trace.getTracerProvider().forceFlush() block and the now-unused trace import. Host awaits Promise.allSettled of hook returns with a 3s race.Diagnostic process.stderr.writelines stay so the next cloud verification can confirmforceFlush done in Xms. They will be removed in a follow-up before v0.1.8 proper.Typecheck: 7/7 packages green.


Summary by cubic

Fixes dropped OTel spans during shutdown by making plugin shutdown hooks async and removing the race caused by early SDK teardown. The host now awaits plugin flushes with a 3s cap, and bcode-laminar flushes its own processor reliably.

  • Bug Fixes
    • shutdown hook now supports void | Promise<void>; host awaits all hooks with a 3s timeout.
    • bcode-laminar shutdown ends open turn spans, then returns processor.forceFlush() via closure (no global provider lookup).
    • Removed sdk.shutdown() from server.instance.disposed to avoid unregistering the provider and closing the BSP prematurely.
    • Dropped trace.getTracerProvider().forceFlush() fallback and the unused trace import; the proxy provider doesn’t expose forceFlush.
    • Kept temporary stderr diagnostics to verify flush timing; to be removed later.

Written for commit a6e7a87. Summary will update on new commits. Review in cubic

…k.shutdown bus race

rc3 diagnostic identified two compounding bugs:

1. bcode-laminar's server.instance.disposed bus handler awaits sdk.shutdown(), which unregisters the global TracerProvider AND closes the BatchSpanProcessor. In headless bcode run mode this fires before the top-level finally, so by the time the sync shutdown hook runs the provider is gone and the BSP queue is dropped.

2. The top-level finally fell back to trace.getTracerProvider().forceFlush(), but the OTel API's ProxyTracerProvider does not expose forceFlush, so even when the global was still registered the call was a no-op. Diagnostic stderr line: '[bcode] shutdown: no forceFlush on global provider'.

Fix:

- Change Hooks.shutdown return type to void | Promise<void> so plugins can return a Promise the host awaits.

- Have bcode-laminar's shutdown end any open turn spans then return processor.forceFlush() directly. Closure ref to the processor bypasses the broken global lookup entirely.

- Remove the sdk.shutdown() / global-unregister call from the server.instance.disposed bus handler. That handler now only ends remaining spans; the sync hook owns drain.

- Drop the trace.getTracerProvider().forceFlush() fallback from src/index.ts and the now-unused trace import.

Diagnostic stderr lines stay in place; will be removed in a follow-up after V4 staging verifies the turn parent span lands.
@Alezander9 Alezander9 merged commit 5d9f2cb into main May 17, 2026
2 checks passed
@Alezander9 Alezander9 deleted the alex/v4-async-shutdown-drain branch May 17, 2026 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant