Summary
After the machine sleeps and wakes, the Coder Connect tunnel can stay unusable for several minutes: new SSH dials fail with i/o timeout until magicsock's periodic re-STUN re-homes the path on its own. A short, same-network wake often produces no netmon link-change event, so the daemon's existing linkChange() recovery (Rebind + ReSTUN) never fires.
The same gap was first observed on macOS (coder/coder#26736), but it is OS-agnostic: the daemon-side fallback timer also stops after 45s idle, and sleep is idle by definition, so on wake there is no scheduled re-STUN until another trigger fires.
Background
coder/coder PR coder/coder#26739 adds the daemon-side hook. It introduces a new CoderVPN RPC (WakeRequest / WakeResponse, tunnel protocol 1.3) whose handler calls tailnet.Conn.Rebind() (magicConn.Rebind() + magicConn.ReSTUN("wake")), the same recovery path a major link change triggers.
The daemon side only exposes the hook. Coder Desktop must actually emit it. This is the Windows counterpart of coder/coder-desktop-macos#260.
What's needed in coder-desktop-windows
- Subscribe to a system resume event. In .NET this is
Microsoft.Win32.SystemEvents.PowerModeChanged with PowerModes.Resume; for a service/headless context without a message pump, register for WM_POWERBROADCAST (PBT_APMRESUMESUSPEND / PBT_APMRESUMEAUTOMATIC) via RegisterPowerSettingNotification.
- On resume, send a
ManagerMessage with the new WakeRequest over the existing CoderVPN tunnel RPC channel.
- Only send when the negotiated tunnel protocol version is
>= 1.3 (older daemons won't handle the message). Regenerate the C# protobuf bindings from the updated vpn.proto once the coder/coder PR merges.
- Optionally surface
WakeResponse.success / error_message in debug logs.
This is an event-driven kick on a known OS event, not a health check or poll. It forces path re-discovery and never tears down a live tunnel.
Refs
Summary
After the machine sleeps and wakes, the Coder Connect tunnel can stay unusable for several minutes: new SSH dials fail with
i/o timeoutuntil magicsock's periodic re-STUN re-homes the path on its own. A short, same-network wake often produces no netmon link-change event, so the daemon's existinglinkChange()recovery (Rebind+ReSTUN) never fires.The same gap was first observed on macOS (coder/coder#26736), but it is OS-agnostic: the daemon-side fallback timer also stops after 45s idle, and sleep is idle by definition, so on wake there is no scheduled re-STUN until another trigger fires.
Background
coder/coder PR coder/coder#26739 adds the daemon-side hook. It introduces a new CoderVPN RPC (
WakeRequest/WakeResponse, tunnel protocol1.3) whose handler callstailnet.Conn.Rebind()(magicConn.Rebind()+magicConn.ReSTUN("wake")), the same recovery path a major link change triggers.The daemon side only exposes the hook. Coder Desktop must actually emit it. This is the Windows counterpart of coder/coder-desktop-macos#260.
What's needed in coder-desktop-windows
Microsoft.Win32.SystemEvents.PowerModeChangedwithPowerModes.Resume; for a service/headless context without a message pump, register forWM_POWERBROADCAST(PBT_APMRESUMESUSPEND/PBT_APMRESUMEAUTOMATIC) viaRegisterPowerSettingNotification.ManagerMessagewith the newWakeRequestover the existing CoderVPN tunnel RPC channel.>= 1.3(older daemons won't handle the message). Regenerate the C# protobuf bindings from the updatedvpn.protoonce the coder/coder PR merges.WakeResponse.success/error_messagein debug logs.This is an event-driven kick on a known OS event, not a health check or poll. It forces path re-discovery and never tears down a live tunnel.
Refs