Repository navigation
fix(relay): end a socket once when its peer vanished without a close - #2844
Conversation
A phone or PC that drops off the network never answers the relay's close, so Cloudflare keeps listing the socket until the connection times out. A Durable Object instance after hibernation did not know the room had ended it: every idle alarm closed it again, told the PC the client disconnected again and reported its usage again, and the room stayed in memory between alarms instead of hibernating. The room now marks a socket ended in its attachment before closing it, and skips sockets marked so.
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 44 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
…nded A frame a vanished peer sent before the close can still be delivered after the Durable Object woke again; it is no longer passed on, and ending the socket again sends no second disconnected or usage report.
|
Reviews of this PR:
Validation at a88816f: |
|
Merge note: relay change, owner-delegated. omo CLEAR at this head, Codex findings reproduced and fixed, review threads resolved, required checks green. The relay deploy follows with the other relay PRs. |
|
Merge note: relay hibernation fix (vanished peers no longer keep rooms awake; 93% of DO active time on 11-04). Reproduced before/after on a test Worker. omo CLEAR at this head, Codex MEDIUM fixed, required checks green. Relay deploy follows. |
Keeps both: the PC's early WELCOME is now marked provisional. A HELLO that offers pairing by comparing digits (#2696) gets a second, final WELCOME with what the PC selects, and a phone comparing digits waits for that one. Warm sockets use the room's end() with #2844's ended mark, and a bound warm socket goes through the PC's shared data-socket path with the pairing deadline.
Change
A phone or PC that drops off the network without closing its relay socket (app suspended, Wi-Fi gone) never answers the close the relay sends it. Cloudflare keeps listing such a socket in
getWebSockets()until the connection times out, about 15 minutes. A Durable Object instance woken after hibernation did not know the room had already ended that socket, so every idle alarm (about every 2 minutes):{"type":"disconnected"}for the sameconnection_id,The room now records
endedin a socket's attachment before closing it.peers()skips such sockets, and a laterwebSocketClose/webSocketErrorfor one is a no-op. A failed send ends the socket through the same path. The wire protocol, close codes, limits and end-to-end encryption are unchanged.Evidence
Cloudflare analytics for the hosted relay on 2026-11-04: of 125.7 hours of Durable Object active time, 116.9 hours (93%) were alarm invocations that each ran 110-120 s, in 10-60 minute streaks per room. The most expensive room was active for 6.8 hours with 1.2 s of CPU.
Reproduced on a throwaway Worker running this relay (same account, workers.dev), with a PC on the host and a phone in a Docker container whose network was disconnected silently:
disconnectedheard by the PCHealthy peers (idle PC, a pair with traffic, SIGSTOPped peers with TCP still up) never showed it, before or after.
Validation
bun test ./relay: 65 pass. The new test (a socket closed to a peer that vanished stays ended across an eviction) fails on main: the socket was closed twice.bun run check fast: passed.check full, native Windows (relay-only change).