Skip to content

EXPERIMENT (do not merge): BASELINE control for #15017 (pre-fix, pre-skip) - #15001

Closed
petebacondarwin wants to merge 2 commits into
mainfrom
exp/dev-registry-crash-bisect
Closed

EXPERIMENT (do not merge): BASELINE control for #15017 (pre-fix, pre-skip)#15001
petebacondarwin wants to merge 2 commits into
mainfrom
exp/dev-registry-crash-bisect

Conversation

@petebacondarwin

@petebacondarwin petebacondarwin commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Scratch harness. Not for merge. Control arm for #15017.

Pre-fix and pre-skip dev-registry fixture (both cyclic tail_consumers restored, #15018's Windows skip reverted) plus a temporary harness that runs only @fixture/dev-registry, six times, uncached, with a per-iteration tally.

arm Windows result
#15017 (fix) pass=6 fail=0, 30/30 tests each, 0 std::terminate, 0 timeouts, durations 237-250s
pre-fix + pre-skip (this run) measuring

An earlier attempt at this control was void: #15018 landed mid-experiment and the PR merge ref picked it up, so all 27 tests were skipped on Windows (↓ 27 tests | 27 skipped, 4.7s per iteration).

Search the job log for TALLY and ITERATION n RESULT.

@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 5dbc2f2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@ask-bonk ask-bonk 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.

I'm Bonk, and I've done a quick review of your PR.

Experimental (do-not-merge) branch that bisects the Windows dev-registry workerd crash; alongside the diagnostic fixture test it also makes real, changeset-bearing changes to Miniflare so that a fatal kj crash banner and its stack trace are surfaced at error level, and warns (with a count) when workerd is restarted after a crash.

The production changes are well-tested. One real (low-severity) logic issue in the crash-report state machine, noted inline. Everything else looks good.

Since this is marked "do not merge", the note below is mainly relevant if the Miniflare structured-logs.ts change is later split out into a mergeable PR.

}

// An ordinary log line means the crash report (if any) is complete.
reportingFatalCrash = false;

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.

reportingFatalCrash is only cleared here, by an ordinary (non-internal) log line. The isAddressInUse (line 149) and isAccessViolation (line 168) branches early-return without clearing it, and both represent a distinct workerd event rather than a continuation of the crash report.

As a result, after a fatal banner, if the next internal line is an address-in-use / access-violation — or if the stream later emits any unrelated hex-stack internal line before a normal log line arrives — the flag stays set and those subsequent internal stacks get re-emitted as error even though they aren't part of the original crash report.

Consider clearing reportingFatalCrash = false; inside those two early-return branches (or scoping the "keep" behaviour to only the symbolizer-notice / stack: lines) so only the diagnostics that immediately follow the banner are surfaced. Your new test "address-in-use errors are still swallowed, even during a crash report" ends right after the address-in-use line, so it doesn't currently exercise the leak.

@ask-bonk

ask-bonk Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully to PR #15001.

Summary of what I did:

  • Verified the trigger PR (EXPERIMENT (do not merge): BASELINE control for #15017 (pre-fix, pre-skip) #15001, branch exp/dev-registry-crash-bisect).
  • Reviewed all 6 changed files, focusing on the shipping Miniflare production changes (structured-logs.ts, index.ts) since the diagnostic fixture test is explicitly marked do-not-merge.
  • Posted one COMMENT review with a single inline issue: the reportingFatalCrash state flag in structured-logs.ts is only cleared by an ordinary non-internal log line, so the isAddressInUse / isAccessViolation early-returns leave it set, potentially re-emitting unrelated internal hex-stack lines as error. Suggested clearing the flag in those terminal branches and noted the existing test doesn't cover the leak.

Everything else (crash-count warning logic, moving the handler creation out of the per-chunk loop to preserve cross-line state, and the test coverage) looked correct.

github run

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

✅ All changesets look good

@pkg-pr-new

pkg-pr-new Bot commented Aug 3, 2026

Copy link
Copy Markdown
@cloudflare/autoconfig

npm i https://pkg.pr.new/@cloudflare/autoconfig@15001

@cloudflare/build-output-utils

npm i https://pkg.pr.new/@cloudflare/build-output-utils@15001

@cloudflare/config

npm i https://pkg.pr.new/@cloudflare/config@15001

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@15001

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/@cloudflare/deploy-helpers@15001

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@15001

miniflare

npm i https://pkg.pr.new/miniflare@15001

@cloudflare/pages-functions

npm i https://pkg.pr.new/@cloudflare/pages-functions@15001

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@15001

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@15001

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@15001

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@15001

@cloudflare/workers-auth

npm i https://pkg.pr.new/@cloudflare/workers-auth@15001

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@15001

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@15001

wrangler

npm i https://pkg.pr.new/wrangler@15001

commit: 5dbc2f2

@petebacondarwin

Copy link
Copy Markdown
Contributor Author

Root cause narrowed to a minimal reproducer

Twelve Windows CI rounds. The trigger is now pinned down exactly:

A dev session that names an assets-enabled worker from another session as its tail_consumer aborts workerd with *** std::terminate() called with no exception when that peer session dies abruptly.

The isolating round

Victim is exported-handler; a peer is started, allowed to register, then SIGKILLed, repeatedly.

Victim's tail consumer Binds the peer Crashed
the assets peer yes 4/4
none yes 0/4 (16 cycles)
a non-assets peer yes 0/4 (18 cycles)
the assets peer no 4/4

Dropping the tail consumer stops it. Pointing the tail consumer at a peer without assets stops it. Removing the service binding changes nothing. Reproduced twice more since, always 4/4 vs 0/4.

Related earlier evidence: killing an assets peer the victim has no relationship with is clean (0/6, 28 cycles), and killing a bound non-assets peer is clean (0/6, 23 cycles).

Ruled out

Hypothesis Result
Traffic over the service binding not required — idle sessions crash
Dev-server restarts 0/3 with 7–10 forced restarts and no peer
Registry file churn without a live peer 0/3
Idle session count (2/3/4), port contention, start order, vite vs wrangler 0/41
CPU starvation with a live peer 0/3
Tail-forwarding fix (#14993) 8/8 still crashed
Routing tail past the assets RPC-proxy hop 4/4 and 3/4 still crashed

The last two are worth emphasising: neither the unhandled rejection in the dev-registry proxy's tail() nor the extra RPCProxyWorker.tail() hop is responsible. Bypassing the hop so an assets peer is tailed exactly like a non-assets peer left the crash rate unchanged, even though tailing a non-assets peer is reliably clean — so the difference lives deeper than the JS routing, most likely in workerd's teardown of tail wiring when the consumer's process vanishes.

Why CI is affected

fixtures/dev-registry has exported-handler tailing worker-entrypoint-with-assets, and the harness SIGKILLs session process trees at test teardown — exactly this pattern. The abort costs ~30s of dev-server restart, which is what blows the 50s test timeout.

The stack is byte-identical across every crash once ASLR bases are normalised, and unsymbolized ($LLVM_SYMBOLIZER is unset on the runners and release workerd is stripped).

@petebacondarwin
petebacondarwin force-pushed the exp/dev-registry-crash-bisect branch from 8562bbd to 350ee29 Compare August 4, 2026 15:18
@petebacondarwin petebacondarwin changed the title EXPERIMENT (do not merge): bisect Windows dev-registry workerd crash EXPERIMENT (do not merge): validate the dev-registry teardown fix on Windows Aug 4, 2026
@petebacondarwin
petebacondarwin force-pushed the exp/dev-registry-crash-bisect branch from 350ee29 to 7857df6 Compare August 4, 2026 16:02
@petebacondarwin petebacondarwin changed the title EXPERIMENT (do not merge): validate the dev-registry teardown fix on Windows EXPERIMENT (do not merge): BASELINE control for the dev-registry teardown fix Aug 4, 2026
…per-iteration tally

Not for merge. Turbo runs the fixtures suite with --concurrency=2 and no
--continue, so an unrelated fixture flake aborts the job before dev-registry
executes (which is exactly what happened on the first run of #15017). This
harness isolates dev-registry and repeats it so a single round of CI yields a
usable sample instead of one coin flip.
Measures the baseline Windows flake rate under the same 6x harness. Reverts
both the teardown fix and #15018's Windows skip, so the original cyclic
tail_consumers are back and the tests actually execute on Windows.
@petebacondarwin
petebacondarwin force-pushed the exp/dev-registry-crash-bisect branch from 7857df6 to 5dbc2f2 Compare August 4, 2026 16:31
@petebacondarwin petebacondarwin changed the title EXPERIMENT (do not merge): BASELINE control for the dev-registry teardown fix EXPERIMENT (do not merge): BASELINE control for #15017 (pre-fix, pre-skip) Aug 4, 2026
@github-project-automation github-project-automation Bot moved this from Untriaged to Done in workers-sdk Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants