Repository navigation
Stand the daemon heartbeat down while the hub is reconnecting - #876
Conversation
The heartbeat and SignalR's automatic reconnect were two reconnect drivers racing: a ping during a reconnect threw, the loop forced a reconnect that cancelled the one in flight, and the connection never converged. Ping and force-reconnect only while Connected.
PR Summary by QodoPrevent heartbeat reconnect races during SignalR recovery
AI Description
Diagram
High-Level Assessment
Files changed (3)
|
Code Review by Qodo
1.
|
The invoke failure can be seen before HubState transitions, so gating the force on IsConnected still raced. A ping that throws means SignalR already owns recovery, so stand down on any throw; only a hung ping (deadline) forces a reconnect.
|
Ran a Codex review of this branch ( Qodo separately raised a valid High: sampling |
Closes #868 — AI-2692
What & why
When the daemon's server connection dropped, it could not recover on its own even after the credential was valid again: it spun in a self-sustaining reconnect storm that only a daemon restart cleared. The daemon drives reconnection from two controllers — SignalR's
WithAutomaticReconnectand the heartbeat loop — and while SignalR was mid-reconnect the connection was "not active", so every heartbeat ping threw, and the loop forced a reconnect that cancelled the negotiate the automatic reconnect had in flight, which kept the connection down, which made the next ping throw. The heartbeat now stands down whenever the hub is notConnected: it neither pings nor force-reconnects, leavingWithAutomaticReconnectandOnClosedto own recovery. It still force-reconnects a hung-but-Connectedtransport (the case it exists for) — a ping that times out while the hub reports Connected.Where to look
Two guards in
DaemonHeartbeatLoop.TickAsync: the tick skips entirely whenIsConnectedis false, andSafeForceReconnectAsyncre-checksIsConnectedso a connection that drops mid-ping does not trigger a force that races the reconnect already starting.IDaemonHeartbeatPortgainedIsConnected, implemented byServerConnectionasHubState == Connected.Verification
DaemonHeartbeatLoopTests(12): a not-Connected hub skips without pinging or forcing; a connection that drops mid-ping does not force; the existing Connected-path cases (hung ping and slot-displacement) are unchanged.