Repository navigation
cellb: a Worker's unhandled rejections are the Worker's, not the Node process's - #15
Merged
Merged
Conversation
… process's On workerd and celld a promise the Worker leaves rejected is the Worker's affair (workerd logs it, celld ignores it). On Node the Worker shares the host's process, so such a rejection reached the process's `unhandledRejection` listeners: vitest counted the four that workerd's vendored tests leave (`assert.rejects(…)` unawaited) as errors and `vitest run` exited 1 with every test passing, which stopped the root `pnpm test`. Each Worker event (Durable Object events through the runtime's events root, the stateless fetch, and host-dispatched code through the new `runtime.runEvent`, which cron triggers use) now runs in a scope that names its runtime. Node calls `unhandledRejection` listeners in the rejected promise's async context, so a hook on `process.emit` finds the scope and hands the rejection to the runtime's `onUnhandledRejection` instead. The default writes one line on stderr, outside the Worker's console, so recorded user logs do not change. Rejections outside any Worker reach the process as before. Browsers are unaffected (a Worker has a worker of its own there). test/p20 covers fetch (before and after an await), a Durable Object method, runEvent, the host's own rejections, and the default report. The root README's note is updated: the root `pnpm test` now runs every workspace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SXJQA3LbggJHi5qZBpUKe8
…8do-worker-rejections
mkotelnikov
changed the base branch from
ccr-ab3c0d30-6du8do-examples-dir
to
main
October 28, 2026 07:04
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #14: the base branch is #14's, so the diff shows only this change. Merge #14 first.
Problem
On workerd and celld, a promise the Worker leaves rejected is the Worker's affair: workerd logs it, celld ignores it. On Node, the Worker shares the host's process, so such a rejection reached the process's
unhandledRejectionlisteners.workerd's vendored Durable Object tests leave four of them (
assert.rejects(…)unawaited). vitest counted them as errors, sovitest runinpackages/cellbexited 1 with every test passing, and the rootpnpm teststopped there.Change
src/core/worker-rejections.ts(new, Node only): every Worker event runs in anAsyncLocalStoragescope naming its runtime. Node callsunhandledRejectionlisteners in the rejected promise's async context, so a hook onprocess.emitfinds the scope and passes the rejection to the runtime'sonUnhandledRejectioninstead of the process. Rejections outside any Worker reach the process as before. Browsers are unaffected: a Worker runs in its own worker there, and the scope is a no-op.fetch;runtime.runEvent(fn), which cron triggers now use;CellRuntimeOptions.onUnhandledRejection: the default writes one line on stderr,[cellb] <script>: unhandled rejection in Worker code: …, outside the Worker's console, so the user logs compared with celld's recordings do not change.docs/celld-compatibility.mddescribes the behaviour; the root README's note now explains the stderr lines instead of the exit-1.fake-openaimove (packages/→examples/), on Examples move to examples/; the root README gets the comparison with celld #14's branch.Tests
test/p20-worker-rejections.test.ts: rejections from afetch(before and after anawait), a Durable Object method andrunEventreachonUnhandledRejectiononly; the host's own rejections still reach the process; the default writes the stderr line and nothing toconsole.error.p09-celld-conformancenow exits 0. Its four rejections are reported under the Worker that raised them (wd-actor-stub), no longer attributed to the test vitest was running.Root
pnpm testexits 0:Interop: 123 passed, 6 expected fail; exit 0.
Chromium: 208 passed, 1 failed, 15 skipped. The failure was
tabs.spec.ts › a restarted ServiceWorker gets the shards of every tab back(Failed to fetcharound the ServiceWorker restart). It passed 5 out of 5 when rerun on this branch, and this change does nothing in browsers.Flue in the browser: 8 passed.
Lint and typecheck are clean in all 4 workspaces.
Generated by Claude Code