fix: Survive a failed WebView2 init and a stale adopted routing entry - #30
Merged
Merged
Conversation
Two faults that surfaced together when a manager running 100+ profiles took an update: the successor came back with a grey window behind a "Failed to initialize WebView2 ... RPC_E_DISCONNECTED" dialog, and then relaunched every profile that was already running. WebView2 serves one user data folder from one browser process, and a client whose browser process goes away mid-initialization gets RPC_E_DISCONNECTED. The folder was a fixed path under %LOCALAPPDATA%, so every manager on the machine shared a browser process and whichever instance owned it could take the others' windows down when it exited. Handoff adds a second overlap the port cannot separate, since a successor deliberately inherits its predecessor's port. On top of that a single failure was terminal: OnFormLoad showed a MessageBox and gave up, leaving a permanently blank window over a server that was running fine. - Partition the user data folder by server port, so managers running side by side no longer share a browser process. Two managers cannot hold the same port concurrently, so it is a sound instance key. - Retry initialization four times with linear backoff, then offer Retry rather than only OK, and say plainly that the profiles are unaffected and the web UI is still reachable. Each retry runs on a fresh WebView2 control: a control binds the environment from its first EnsureCoreWebView2Async call and rejects a different one later, which is exactly what a retry needs to supply. The relaunches were a routing entry inherited across the handoff. A successor restores each profile's entry from the predecessor's manifest, so it inherits whatever the predecessor believed — and a predecessor built before the handle was tracked on the instance reverse-looked it up from a map that leaked a dead row per game exit, returning an arbitrary one. The adopted games then sent from a window the successor was not listening on, no heartbeats arrived, and the watchdog killed and relaunched all of them about a minute later. Fixing the lookup does not help here because the predecessor is the old build by definition, so the successor has to be able to recover on its own. - On a missed heartbeat, check the profile's routing entry against the window its game actually owns and re-register if they disagree, granting one interval before counting the miss. A wrong entry and a dead bot are indistinguishable to the watchdog, and killing a healthy game over one is the worst available response. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Two faults that surfaced together when a manager running 100+ profiles took an update: the successor came back with a grey window behind a "Failed to initialize WebView2 ... RPC_E_DISCONNECTED" dialog, and then relaunched every profile that was already running.
WebView2 serves one user data folder from one browser process, and a client whose browser process goes away mid-initialization gets RPC_E_DISCONNECTED. The folder was a fixed path under %LOCALAPPDATA%, so every manager on the machine shared a browser process and whichever instance owned it could take the others' windows down when it exited. Handoff adds a second overlap the port cannot separate, since a successor deliberately inherits its predecessor's port. On top of that a single failure was terminal: OnFormLoad showed a MessageBox and gave up, leaving a permanently blank window over a server that was running fine.
The relaunches were a routing entry inherited across the handoff. A successor restores each profile's entry from the predecessor's manifest, so it inherits whatever the predecessor believed — and a predecessor built before the handle was tracked on the instance reverse-looked it up from a map that leaked a dead row per game exit, returning an arbitrary one. The adopted games then sent from a window the successor was not listening on, no heartbeats arrived, and the watchdog killed and relaunched all of them about a minute later. Fixing the lookup does not help here because the predecessor is the old build by definition, so the successor has to be able to recover on its own.