Skip to content

test(node): Fix flaky ANR stop-and-restart test with deterministic worker-ready signal - #23514

Draft
mydea wants to merge 1 commit into
developfrom
fn/fix-anr-worker-restart-flake
Draft

test(node): Fix flaky ANR stop-and-restart test with deterministic worker-ready signal#23514
mydea wants to merge 1 commit into
developfrom
fn/fix-anr-worker-restart-flake

Conversation

@mydea

@mydea mydea commented Aug 24, 2026

Copy link
Copy Markdown
Member

The anr/stop-and-start integration test restarts the ANR worker and then blocks the event loop, expecting the restarted worker to sample and report the ANR. The gate before longWork was ineffective, so on slow CI the event loop could block before the new worker had reconnected — and the ANR was missed, making the test flaky.

Root cause

waitForDebuggerReady polls inspector.url(). That works for the initial worker start (where inspector.open(0) flips inspector.url() from unset to set), but it cannot gate a restart:

  • The ANR integration opens the main-thread inspector once and never calls inspector.close(), so inspector.url() stays truthy across stopWorker()/startWorker(). The poll returns immediately and only a fixed ~200ms delay remains.
  • _startWorker is async (it awaits getContexts), so when the poll passes the new worker may not even be spawned yet.

The main thread has no observable signal that the new worker's InspectorSession has reconnected, so any main-thread poll or fixed delay is a race.

Change

The worker now posts a worker-ready message once it is fully set up (inspector session connected when capturing stack traces, watchdog armed, message handler registered). The integration tracks this and exposes an internal waitUntilWorkerReady(), which the restart path awaits instead of relying on a fixed delay. This makes readiness deterministic rather than timing-dependent.

The flake exists on develop too (the restart path there blocks after a bare setTimeout(..., 0)), which is why this is a standalone fix rather than part of any feature branch.

…y signal

The `stop-and-start` ANR test restarts the worker and then blocks the event loop,
expecting the restarted worker to sample and report the ANR. It previously ran
`longWork` almost immediately after `startWorker()`.

`waitForDebuggerReady` (polling `inspector.url()`) cannot gate this: the ANR
integration opens the main-thread inspector once and never closes it, so
`inspector.url()` stays truthy across restarts and the poll returns immediately.
`_startWorker` is also async, so the new worker may not even be spawned yet. On
slow CI the event loop can block before the new worker reconnects its inspector
session, and the ANR is missed.

The worker now posts a `worker-ready` message once it is fully set up, and the
integration exposes `waitUntilWorkerReady()` so the restart path can await the
new worker's actual readiness instead of a fixed delay.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 30.3 kB - -
@sentry/browser - with treeshaking flags 28.47 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 26.81 kB - -
@sentry/browser (incl. Tracing) 48.62 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 48.64 kB - -
@sentry/browser (incl. Tracing, Profiling) 51.51 kB - -
@sentry/browser (incl. Tracing, Replay) 88.02 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.42 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 92.74 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 105.45 kB - -
@sentry/browser (incl. Feedback) 47.65 kB - -
@sentry/browser (incl. sendFeedback) 35.13 kB - -
@sentry/browser (incl. FeedbackAsync) 40.28 kB - -
@sentry/browser (incl. Metrics) 31.24 kB - -
@sentry/browser (incl. Logs) 31.52 kB - -
@sentry/browser (incl. Metrics & Logs) 32.15 kB - -
@sentry/react 32.09 kB - -
@sentry/react (incl. Tracing) 50.81 kB - -
@sentry/vue 35.34 kB - -
@sentry/vue (incl. Tracing) 50.61 kB - -
@sentry/svelte 30.33 kB - -
CDN Bundle 31.61 kB - -
CDN Bundle (incl. Tracing) 48.96 kB - -
CDN Bundle (incl. Logs, Metrics) 33.8 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 50.87 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 74.31 kB - -
CDN Bundle (incl. Tracing, Replay) 86.53 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.37 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 92.24 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94.18 kB - -
CDN Bundle - uncompressed 93.84 kB - -
CDN Bundle (incl. Tracing) - uncompressed 146.82 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 100.14 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 152.51 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 229.08 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 266.08 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 271.76 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 279.78 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 285.45 kB - -
@sentry/nextjs (client) 53.36 kB - -
@sentry/sveltekit (client) 49.04 kB - -
@sentry/core/server 65.56 kB - -
@sentry/core/browser 51.78 kB - -
@sentry/node 117.47 kB +0.02% +23 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 85.18 kB - -
@sentry/node - without tracing 82.02 kB +0.04% +25 B 🔺
@sentry/aws-serverless 91.44 kB +0.03% +20 B 🔺
@sentry/cloudflare (withSentry) - minified 194.61 kB - -
@sentry/cloudflare (withSentry) 481.16 kB - -

View base workflow run

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