refactor(server): reuse client heartbeat for socket liveness

This commit is contained in:
Mohamed Boudra
2026-07-18 13:34:33 +00:00
parent 8cf190e516
commit abe91201f0
10 changed files with 8 additions and 56 deletions
+1 -1
View File
@@ -198,7 +198,7 @@ There is no dedicated welcome message; the server emits a `status` session messa
**Top-level WS envelopes** are `hello`, `recording_state`, `ping`/`pong`, and `session` (which wraps the rich union of session messages).
Client liveness checks use the top-level JSON `ping`/`pong` envelope, not a session RPC or RFC6455 control ping. Current clients advertise `capabilities.application_socket_lease: true` in `hello`, which claims an application-ownership lease for that physical socket immediately; a first JSON `ping` also opts in clients that did not advertise the capability. All later inbound activity renews a claimed lease, and the daemon forcibly terminates the socket if the lease expires. A legacy or raw socket that advertises neither the capability nor an application `ping` never enters this lease and is not closed for omitting one. Session RPC timeouts are operation failures and must not be treated as proof that the socket is dead.
Client liveness checks use the top-level JSON `ping`/`pong` envelope, not a session RPC or RFC6455 control ping. Current clients ping every 10 seconds, beginning one interval after connecting. The first ping claims an application-ownership lease for that physical socket, all later inbound activity renews it, and the daemon forcibly terminates the socket if the lease expires. A legacy or raw socket that never sends an application ping never enters this lease and is not closed for omitting one. Session RPC timeouts are operation failures and must not be treated as proof that the socket is dead.
Every physical send path enforces an 8 MiB outbound high-water mark, including JSON broadcasts, binary terminal frames, and the encrypted relay adapter's asynchronous queue. This sits above the terminal stream's 4 MiB soft backpressure threshold, leaving room for snapshot catch-up before the hard cutoff. JSON is serialized once per broadcast after sockets already at the limit are removed, then its exact byte length is checked for every remaining socket. A frame that would cross the limit is not sent; that physical socket is forcibly terminated without disturbing other sockets attached to the same logical session. Multiple tabs and simultaneous direct and relay paths may legitimately share a client id.