Skip to content

fix(opentelemetry): Use WeakRef for context stored on scope to prevent memory leak#20328

Merged
JPeer264 merged 2 commits intodevelopfrom
jp/fastify-oom
Apr 15, 2026
Merged

fix(opentelemetry): Use WeakRef for context stored on scope to prevent memory leak#20328
JPeer264 merged 2 commits intodevelopfrom
jp/fastify-oom

Conversation

@JPeer264
Copy link
Copy Markdown
Member

closes #20174
closes JS-2106

When using pooled connections (e.g., pg) with OTel instrumentation, patched callbacks can retain references to contexts. Previously, contexts held strong references to scopes, and scopes held strong references back to contexts, creating a circular reference that prevented garbage collection.

This change:

  • Adds a shared WeakRef utility (makeWeakRef/derefWeakRef) in @sentry/core
  • Uses WeakRef for the context stored on scope, breaking the circular reference
  • Refactors tracing/utils.ts to use the shared utility
  • Adds comprehensive unit tests for the WeakRef utility

Load tests with Artillery ran against the reproduction s1gr1d/sentry-js-20174-fastify-memory before and after the fix. With reusing the makeWeakRef and derefWeakRef the memory leak is gone. If it makes more sense to split this up into two PRs (1. exporting makeWeakRef and derefWeakRef and 2. the actual fix, I'm happy to do it)

@JPeer264 JPeer264 requested review from andreiborza and s1gr1d April 15, 2026 11:36
@JPeer264 JPeer264 self-assigned this Apr 15, 2026
@linear-code
Copy link
Copy Markdown

linear-code bot commented Apr 15, 2026

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1142bec. Configure here.

expect(storedRef).toBeDefined();
expect(typeof (storedRef as { deref?: unknown }).deref).toBe('function');
}
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Test conditional makes assertions silently skippable

Low Severity

The test "uses WeakRef when available" wraps all its expect assertions inside if (typeof WeakRef !== 'undefined'). If WeakRef were ever unavailable in the test environment, the test would pass silently without asserting anything. Per the project review rules, conditionals in a single test are discouraged — this could be split into two separate tests (one for when WeakRef is available, one for when it isn't) to ensure assertions always run.

Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 1142bec. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 15, 2026

size-limit report 📦

Path Size % Change Change
@sentry/browser 25.78 kB - -
@sentry/browser - with treeshaking flags 24.27 kB - -
@sentry/browser (incl. Tracing) 42.77 kB -0.01% -1 B 🔽
@sentry/browser (incl. Tracing, Profiling) 47.4 kB - -
@sentry/browser (incl. Tracing, Replay) 81.69 kB +0.01% +1 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 71.22 kB -0.01% -2 B 🔽
@sentry/browser (incl. Tracing, Replay with Canvas) 86.39 kB +0.01% +2 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 98.6 kB +0.01% +1 B 🔺
@sentry/browser (incl. Feedback) 42.59 kB - -
@sentry/browser (incl. sendFeedback) 30.45 kB - -
@sentry/browser (incl. FeedbackAsync) 35.45 kB - -
@sentry/browser (incl. Metrics) 27.07 kB +0.01% +1 B 🔺
@sentry/browser (incl. Logs) 27.2 kB - -
@sentry/browser (incl. Metrics & Logs) 27.89 kB +0.01% +2 B 🔺
@sentry/react 27.53 kB - -
@sentry/react (incl. Tracing) 45.09 kB - -
@sentry/vue 30.61 kB +0.01% +3 B 🔺
@sentry/vue (incl. Tracing) 44.62 kB -0.01% -1 B 🔽
@sentry/svelte 25.8 kB - -
CDN Bundle 28.46 kB - -
CDN Bundle (incl. Tracing) 43.82 kB - -
CDN Bundle (incl. Logs, Metrics) 29.83 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 44.89 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 68.73 kB - -
CDN Bundle (incl. Tracing, Replay) 80.78 kB +0.01% +1 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 81.83 kB +0.01% +2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 86.31 kB +0.01% +1 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 87.34 kB +0.01% +2 B 🔺
CDN Bundle - uncompressed 83.12 kB - -
CDN Bundle (incl. Tracing) - uncompressed 129.95 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 87.27 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 133.36 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 210.63 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 247.21 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 250.6 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 260.12 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 263.51 kB - -
@sentry/nextjs (client) 47.52 kB - -
@sentry/sveltekit (client) 43.24 kB - -
@sentry/node-core 57.94 kB +0.02% +10 B 🔺
@sentry/node 174.72 kB -0.02% -27 B 🔽
@sentry/node - without tracing 97.81 kB +0.03% +22 B 🔺
@sentry/aws-serverless 115.07 kB +0.02% +16 B 🔺

View base workflow run

Copy link
Copy Markdown
Member

@mydea mydea left a comment

Choose a reason for hiding this comment

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

seems reasonable to me!

JPeer264 and others added 2 commits April 15, 2026 15:08
…t memory leak

When using pooled connections (e.g., pg) with OTel instrumentation, patched
callbacks can retain references to contexts. Previously, contexts held strong
references to scopes, and scopes held strong references back to contexts,
creating a circular reference that prevented garbage collection.

This change:
- Adds a shared WeakRef utility (makeWeakRef/derefWeakRef) in @sentry/core
- Uses WeakRef for the context stored on scope, breaking the circular reference
- Refactors tracing/utils.ts to use the shared utility
- Adds comprehensive unit tests for the WeakRef utility

Fixes #20174

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests for getScopesFromContext, setScopesOnContext, setContextOnScope,
and getContextFromScope including WeakRef behavior verification.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@JPeer264 JPeer264 merged commit 3332fec into develop Apr 15, 2026
473 of 477 checks passed
@JPeer264 JPeer264 deleted the jp/fastify-oom branch April 15, 2026 18:28
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.

Memory leak: contextWrapper on ServerResponse.close retains async context across keep-alive connections (Fastify)

2 participants