Auto-recover active sessions after signaling disconnects#321
Auto-recover active sessions after signaling disconnects#321
Conversation
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
|
@Jayian1890 if you can test this due to my sub ended so |
There was a problem hiding this comment.
Pull request overview
Adds bounded automatic recovery in the renderer (App.tsx) to reclaim and reconnect to an existing CloudMatch session after unexpected signaling disconnects (e.g., network/VPN changes), instead of immediately tearing down stream state.
Changes:
- Introduces
SignalingRecoveryState+ helpers to track recovery attempts, delays, explicit shutdown intent, and appId context. - Implements
attemptSessionRecoveryflow that queries active sessions, re-claims the best candidate, and reconnects signaling with a limited retry budget. - Refactors session resume path by extracting
resolveSessionClaimAppIdandapplyClaimedSessionAndConnect, and updates signaling event handling to use recovery ondisconnected.
| setStreamStatus("connecting"); | ||
| signalingRecoveryRef.current.explicitShutdown = false; | ||
| await window.openNow.connectSignaling({ | ||
| sessionId: claimed.sessionId, | ||
| signalingServer: claimed.signalingServer, | ||
| signalingUrl: claimed.signalingUrl, | ||
| }); |
There was a problem hiding this comment.
applyClaimedSessionAndConnect unconditionally clears signalingRecoveryRef.current.explicitShutdown before connecting signaling. If the user hits Stop/Dismiss while a recovery/claim is already past the earlier explicitShutdown checks (e.g., during getActiveSessions/claimSession), this can re-enable signaling and reconnect against user intent. Consider not mutating explicitShutdown here, and instead re-check explicitShutdown (or a recovery generation/abort token) immediately before applying session state and calling connectSignaling.
| } else if (event.type === "disconnected") { | ||
| console.warn("Signaling disconnected:", event.reason); | ||
| const recovered = await attemptSessionRecovery(event.reason).catch((error) => { | ||
| console.error("[Recovery] Signaling recovery failed:", error); | ||
| throw error; | ||
| }); | ||
| if (!recovered) { | ||
| clientRef.current?.dispose(); | ||
| clientRef.current = null; | ||
| setLaunchError({ | ||
| stage: streamStatusToLoadingStage(streamStatusRef.current), | ||
| title: "Session Connection Lost", | ||
| description: "The connection to your running session was lost and could not be restored automatically. Try resuming it again from the app.", | ||
| }); | ||
| resetLaunchRuntime({ keepLaunchError: true, keepStreamingContext: true }); |
There was a problem hiding this comment.
The disconnected handler treats any attemptSessionRecovery result of false as a hard failure and surfaces a user-facing "Session Connection Lost" error. When attemptSessionRecovery returns false because explicitShutdown was set (user-initiated stop/dismiss) or the status is non-recoverable, this can incorrectly show an error UX for an intentional shutdown. Consider explicitly checking signalingRecoveryRef.current.explicitShutdown (or returning a distinct result) and early-returning without setting launchError in that case.
| const markExplicitSignalingShutdown = useCallback((): void => { | ||
| signalingRecoveryRef.current.explicitShutdown = true; | ||
| signalingRecoveryRef.current.inFlight = null; | ||
| }, []); |
There was a problem hiding this comment.
markExplicitSignalingShutdown clears inFlight but does not actually cancel the underlying recovery promise. If a recovery attempt is already running, it can still continue and later call applyClaimedSessionAndConnect, potentially reconnecting after a user stop/dismiss. Consider adding an abort/generation mechanism that the recovery loop (and applyClaimedSessionAndConnect) checks before updating state / reconnecting, rather than only nulling the ref.
Description
Implement bounded automatic recovery for active sessions when signaling disconnects unexpectedly (e.g., after VPN toggle or network path changes). The renderer now attempts to reclaim and reconnect to the same session instead of immediately tearing down state.
Recovery Logic (
src/renderer/src/App.tsx):queue,setup,starting,connecting,streaming)[0ms, 3000ms]before failingsessionId; fall back to matching the trackedappIdif the same session is not foundlaunchErrorand reset to idle stateExplicit Shutdown Guard:
SignalingRecoveryStateref to track recovery attempts and explicit shutdown intentmarkExplicitSignalingShutdowninhandleStopStreamandhandleDismissLaunchErrorto prevent automatic recovery after user-initiated stopsShared Resume Helpers:
resolveSessionClaimAppIdto safely resolve theappIdfor session claimsapplyClaimedSessionAndConnectto centralize session application and signaling connectionclaimAndConnectSessionto use the extracted helpersSignaling Event Handler:
disconnectedevents with a call toattemptSessionRecoveryoffer/streamingtransition