-
[client, proxy] cancel context before stopping engine on embedded client (#6397)
Some checks failedRelease / FreeBSD Port / Build & Test (push) Has been cancelledRelease / release (push) Has been cancelledRelease / release_ui (push) Has been cancelledRelease / release_ui_darwin (push) Has been cancelledRelease / Windows Installer / Build Test (amd64, amd64) (push) Has been cancelledRelease / Windows Installer / Build Test (arm64, arm64) (push) Has been cancelledRelease / Comment release artifacts (push) Has been cancelledRelease / trigger_signer (push) Has been cancelledsync tag / trigger_sync_tag (push) Has been cancelledsync tag / trigger_android_bump (push) Has been cancelledsync tag / trigger_ios_bump (push) Has been cancelledupdate docs / trigger_docs_api_update (push) Has been cancelledreleased this
2026-06-11 03:26:54 +08:00 - Engine.Start takes syncMsgMux with a deferred unlock (engine.go:445) and parks in receiveSignalEvents → WaitStreamConnected (engine.go:1762), which only wakes on
signal-stream connect or client-context cancellation. - When signal never connects, the 30s startup timeout fires and embed.Client.Start's rollback (embed.go:281) called client.Stop() → Engine.Stop, which blocks acquiring
syncMsgMux (engine.go:318). The cancel() that would unpark Start was deferred until Start returned — permanent cycle. RemovePeer calls (g43/g385) then queue behind the
lifecycle mutex. - Notably, embed.Client.Stop and the daemon's cleanupConnection both cancel before stopping — the startup rollback was the only path that didn't.
- Engine.Start takes syncMsgMux with a deferred unlock (engine.go:445) and parks in receiveSignalEvents → WaitStreamConnected (engine.go:1762), which only wakes on
signal-stream connect or client-context cancellation. - When signal never connects, the 30s startup timeout fires and embed.Client.Start's rollback (embed.go:281) called client.Stop() → Engine.Stop, which blocks acquiring
syncMsgMux (engine.go:318). The cancel() that would unpark Start was deferred until Start returned — permanent cycle. RemovePeer calls (g43/g385) then queue behind the
lifecycle mutex. - Notably, embed.Client.Stop and the daemon's cleanupConnection both cancel before stopping — the startup rollback was the only path that didn't.
Downloads
- Engine.Start takes syncMsgMux with a deferred unlock (engine.go:445) and parks in receiveSignalEvents → WaitStreamConnected (engine.go:1762), which only wakes on