Skip to content

Fix node tracer shutdown exceeds shutdownTimeout - #7112

Merged
tim-smart merged 3 commits into
mainfrom
audit/repro-b206fa5d76-node-sdk-tracer-shutdown-timeout
Aug 7, 2026
Merged

Fix node tracer shutdown exceeds shutdownTimeout#7112
tim-smart merged 3 commits into
mainfrom
audit/repro-b206fa5d76-node-sdk-tracer-shutdown-timeout

Conversation

@fubhy

@fubhy fubhy commented Aug 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Bound Node tracer provider release by shutdownTimeout, including a slow or never-resolving shutdown().
  • Kept shutdown guaranteed after forceFlush() by using the same timed Promise-chain pattern as the logger provider.
  • Added a patch changeset for @effect/opentelemetry.

Validation

  • pnpm test --run packages/opentelemetry/test
  • pnpm lint
  • pnpm check

Audit provenance

  • Audit base: b206fa5d7655c1634c9993410a9203f6616a5ca2
  • Finding: relsem-node-tracer-shutdown-timeout

Closes EFF-547

@fubhy fubhy added the audit Findings originating from the Effect runtime correctness audit label Aug 7, 2026
@changeset-bot

changeset-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5172adf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 30 packages
Name Type
@effect/opentelemetry Patch
effect Patch
@effect/ai-anthropic Patch
@effect/ai-openai Patch
@effect/ai-openai-compat Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/openapi-generator Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-deno Patch
@effect/platform-node Patch
@effect/platform-node-shared Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/vitest Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@effect-slopcop effect-slopcop Bot added 4.0 bug Something isn't working labels Aug 7, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The PR title promises a fix, but the current diff only adds the failing reproduction test. The implementation change in packages/opentelemetry/src/NodeSdk.ts is still required.

Reviewed changes

  • Added one regression test in packages/opentelemetry/test/OtelTracer.test.ts that verifies NodeSdk.layerTracerProvider release completes within shutdownTimeout even when the underlying SpanProcessor.shutdown Promise does not resolve.

⚠️ Missing implementation fix

The test correctly fails against main and captures the bug. The fix should move shutdown inside the timed Promise so the timeout actually bounds the release.

In NodeSdk.ts, the current release is:

Effect.promise(() => provider.forceFlush()).pipe(
  Effect.ensuring(Effect.promise(() => provider.shutdown())),
  ...
  Effect.timeoutOption(config?.shutdownTimeout ?? 3000)
)

Because timeoutOption wraps the ensuring chain, interruption still waits for provider.shutdown() to settle, so a stuck shutdown exceeds shutdownTimeout.

The sibling OtelLogger.ts already uses the pattern that avoids this:

Effect.promise(() => provider.forceFlush().finally(() => provider.shutdown())).pipe(
  ...
  Effect.timeoutOption(config?.shutdownTimeout ?? 3000)
)

Adopting the same .finally()-based Promise for the tracer provider release should make the new test pass.

Technical details
# NodeSdk tracer release timeout bug

## Affected sites
- packages/opentelemetry/src/NodeSdk.ts:77-82 — release combines `forceFlush` and `shutdown` with `ensuring`, placing `shutdown` outside the reach of `timeoutOption`.

## Required outcome
- `NodeSdk.layerTracerProvider` release must complete within `shutdownTimeout` even if `provider.shutdown()` never resolves.
- `provider.shutdown()` should still be attempted after `provider.forceFlush()`.

## Suggested approach
Mirror `packages/opentelemetry/src/OtelLogger.ts:187-190`: wrap a single Promise chain `provider.forceFlush().finally(() => provider.shutdown())` with `Effect.ignore`, `Effect.interruptible`, and `Effect.timeoutOption`.

ℹ️ Same shape exists in WebSdk

WebSdk.layerTracerProvider uses the same Effect.ensuring construction without any shutdownTimeout config. That is pre-existing and out of scope here, but worth noting if the fix is intended to cover both platforms.

ℹ️ Nitpicks

  • Add a changeset under .changeset/ once the implementation fix lands; runtime behavior changes require one.
  • Consider strengthening the test assertion at packages/opentelemetry/test/OtelTracer.test.ts:60 to also verify the release succeeded, e.g. assert.isTrue(Exit.isSuccess(completed)), so a failure exit cannot accidentally satisfy the test.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

Comment thread packages/opentelemetry/test/OtelTracer.test.ts Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

The new commits address all three points from the prior review.

Reviewed changes

  • Implemented the tracer provider release fix in packages/opentelemetry/src/NodeSdk.ts: replaced the Effect.ensuring shutdown pattern with a single Effect.promise(() => provider.forceFlush().finally(() => provider.shutdown())) chain, keeping it inside Effect.timeoutOption so the timeout bounds a stuck shutdown.
  • Strengthened the regression test in packages/opentelemetry/test/OtelTracer.test.ts: added assert.isTrue(Exit.isSuccess(completed)) so the test fails if release exits with an error rather than succeeding.
  • Added the patch changeset in .changeset/eff-547-node-tracer-timeout.md for @effect/opentelemetry.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
basic.ts 6.92 KB 6.92 KB 0.00 KB (0.00%)
batching.ts 9.72 KB 9.72 KB 0.00 KB (0.00%)
brand.ts 6.60 KB 6.60 KB 0.00 KB (0.00%)
cache.ts 10.59 KB 10.59 KB 0.00 KB (0.00%)
config.ts 20.88 KB 20.88 KB 0.00 KB (0.00%)
differ.ts 19.74 KB 19.74 KB 0.00 KB (0.00%)
http-client.ts 21.50 KB 21.50 KB 0.00 KB (0.00%)
logger.ts 10.81 KB 10.81 KB 0.00 KB (0.00%)
metric.ts 8.86 KB 8.86 KB 0.00 KB (0.00%)
optic.ts 6.68 KB 6.68 KB 0.00 KB (0.00%)
pubsub.ts 14.86 KB 14.86 KB 0.00 KB (0.00%)
queue.ts 11.54 KB 11.54 KB 0.00 KB (0.00%)
schedule.ts 10.71 KB 10.71 KB 0.00 KB (0.00%)
schema-class.ts 19.45 KB 19.45 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 29.32 KB 29.32 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 25.59 KB 25.59 KB 0.00 KB (0.00%)
schema-string-transformation.ts 13.52 KB 13.52 KB 0.00 KB (0.00%)
schema-string.ts 11.05 KB 11.05 KB 0.00 KB (0.00%)
schema-template-literal.ts 15.35 KB 15.35 KB 0.00 KB (0.00%)
schema-toArbitraryLazy.ts 21.48 KB 21.48 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 23.96 KB 23.96 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 18.70 KB 18.70 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 18.53 KB 18.53 KB 0.00 KB (0.00%)
schema-toFormatter.ts 18.39 KB 18.39 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 22.16 KB 22.16 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 19.05 KB 19.05 KB 0.00 KB (0.00%)
schema.ts 18.69 KB 18.69 KB 0.00 KB (0.00%)
stm.ts 12.59 KB 12.59 KB 0.00 KB (0.00%)
stream.ts 9.67 KB 9.67 KB 0.00 KB (0.00%)

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The implementation fix is correct and consistent with the logger provider, but commit 5172adf removed the only regression test for this fix, leaving the bounded-shutdown behavior with no automated coverage.

Reviewed changes

Since the prior pullfrog review (approved at e329306), one commit landed:

  • Removed the tracer shutdown regression test in packages/opentelemetry/test/OtelTracer.test.ts — deleted the "bounds tracer provider release by shutdownTimeout" case, which was the sole automated verification for this fix.

⚠️ Fix ships without regression coverage

The entire point of this PR is that NodeSdk.layerTracerProvider release now completes within shutdownTimeout even when a span processor's shutdown() Promise never resolves. Removing the test that proved that means nothing will guard the behavior — a future refactor back to the Effect.ensuring construction (or a dropped .finally()) would silently reintroduce the original bug. If the test was dropped because it proved flaky under the test clock, a more reliable variant or a short note recording why it was removed would preserve the intent; the fix is small and targeted enough that dedicated verification is worth retaining.

The change in NodeSdk.ts:77 itself (forceFlush().finally(() => shutdown()) inside timeoutOption) matches OtelLogger.ts:187 exactly, and the changeset accurately describes the runtime behavior change.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Fix it ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@tim-smart
tim-smart merged commit 14278e7 into main Aug 7, 2026
19 of 20 checks passed
@tim-smart
tim-smart deleted the audit/repro-b206fa5d76-node-sdk-tracer-shutdown-timeout branch August 7, 2026 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.0 audit Findings originating from the Effect runtime correctness audit bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants