What versions & operating system are you using?
System:
OS: macOS 26.5.1
CPU: (10) arm64 Apple M5
Memory: 286.09 MB / 24.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.23.1 - /Users/leoli/.nvm/versions/node/v22.23.1/bin/node
npm: 10.9.8 - /Users/leoli/.nvm/versions/node/v22.23.1/bin/npm
pnpm: 10.33.0 - /Users/leoli/.nvm/versions/node/v22.23.1/bin/pnpm
bun: 1.3.14 - /Users/leoli/.bun/bin/bun
Reproduced against workers-sdk commit:
99eb50c
Please provide a link to a minimal reproduction
teamleaderleo#55
Describe the Bug
Miniflare.dispose() currently awaits browser cleanup and ProxyClient.dispose() before it calls Runtime.dispose().
As a result, Runtime.dispose() is reached only after those earlier cleanup awaits fulfill.
If either remains pending, runtime disposal is delayed for as long as that cleanup remains pending, leaving the workerd child running. If either rejects, execution can leave the cleanup sequence before Runtime.dispose() is called at all.
Reproduction
I reproduced this with a Miniflare instance and workerd child by holding ProxyClient.dispose() pending for one second.
Current behavior:
[fieldwork-456] before-release {
"observedForMs": 1002,
"workerdPid": 85892,
"killRequested": false,
"childStillAlive": true,
"disposeSettled": false
}
After releasing proxy cleanup, execution reaches runtime disposal and the child exits with SIGKILL:
[fieldwork-456] after-release {
"workerdPid": 85892,
"exitCode": null,
"signalCode": "SIGKILL",
"disposeSettled": true
}
Expected behavior
Independent browser/proxy cleanup shouldn't control whether Miniflare requests termination of the workerd process it owns.
Runtime.dispose() already requests SIGKILL synchronously and returns the child-exit promise, so runtime disposal can be started before awaiting independent cleanup.
The outer Miniflare.dispose() can remain pending until the other cleanup completes.
Direction
I tested starting runtime disposal before the independent cleanup awaits, retaining the returned exit promise, and awaiting it before Miniflare.dispose() settles.
Under the same one-second blocked proxy cleanup:
[fieldwork-456] before-release {
"observedForMs": 1001,
"workerdPid": 86121,
"killRequested": true,
"childStillAlive": false,
"disposeSettled": false
}
So workerd has already terminated, while Miniflare correctly continues waiting for the remaining cleanup.
A draft implementation and regression tests following this direction are here:
teamleaderleo#55
There is an additional question of whether every later teardown owner should be attempted after an independent cleanup failure, but the scope of this report is limited to ensuring that an earlier independent cleanup operation won't delay or skip owned runtime termination.
Please provide any relevant error logs
There isn't an error log associated with the pending-cleanup reproduction. The relevant observed process state is:
Current behavior:
[fieldwork-456] before-release {
"observedForMs": 1002,
"workerdPid": 85892,
"killRequested": false,
"childStillAlive": true,
"disposeSettled": false
}
After releasing proxy cleanup:
[fieldwork-456] after-release {
"workerdPid": 85892,
"exitCode": null,
"signalCode": "SIGKILL",
"disposeSettled": true
}
Candidate behavior under the same one-second hold:
[fieldwork-456] before-release {
"observedForMs": 1001,
"workerdPid": 86121,
"killRequested": true,
"childStillAlive": false,
"disposeSettled": false
}
What versions & operating system are you using?
System:
OS: macOS 26.5.1
CPU: (10) arm64 Apple M5
Memory: 286.09 MB / 24.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.23.1 - /Users/leoli/.nvm/versions/node/v22.23.1/bin/node
npm: 10.9.8 - /Users/leoli/.nvm/versions/node/v22.23.1/bin/npm
pnpm: 10.33.0 - /Users/leoli/.nvm/versions/node/v22.23.1/bin/pnpm
bun: 1.3.14 - /Users/leoli/.bun/bin/bun
Reproduced against workers-sdk commit:
99eb50c
Please provide a link to a minimal reproduction
teamleaderleo#55
Describe the Bug
Miniflare.dispose()currently awaits browser cleanup andProxyClient.dispose()before it callsRuntime.dispose().As a result,
Runtime.dispose()is reached only after those earlier cleanup awaits fulfill.If either remains pending, runtime disposal is delayed for as long as that cleanup remains pending, leaving the
workerdchild running. If either rejects, execution can leave the cleanup sequence beforeRuntime.dispose()is called at all.Reproduction
I reproduced this with a Miniflare instance and
workerdchild by holdingProxyClient.dispose()pending for one second.Current behavior:
After releasing proxy cleanup, execution reaches runtime disposal and the child exits with
SIGKILL:Expected behavior
Independent browser/proxy cleanup shouldn't control whether Miniflare requests termination of the
workerdprocess it owns.Runtime.dispose()already requestsSIGKILLsynchronously and returns the child-exit promise, so runtime disposal can be started before awaiting independent cleanup.The outer
Miniflare.dispose()can remain pending until the other cleanup completes.Direction
I tested starting runtime disposal before the independent cleanup awaits, retaining the returned exit promise, and awaiting it before
Miniflare.dispose()settles.Under the same one-second blocked proxy cleanup:
So
workerdhas already terminated, while Miniflare correctly continues waiting for the remaining cleanup.A draft implementation and regression tests following this direction are here:
teamleaderleo#55
There is an additional question of whether every later teardown owner should be attempted after an independent cleanup failure, but the scope of this report is limited to ensuring that an earlier independent cleanup operation won't delay or skip owned runtime termination.
Please provide any relevant error logs
There isn't an error log associated with the pending-cleanup reproduction. The relevant observed process state is: