joule-moq-relay: each end of a WebSocket session pings the other every 30 s #513

Merged
dcharlot merged 1 commit from wai/relay-ws-ping into main 2026-10-27 16:14:29 -04:00
Owner

The edge relay's link to its home relay runs over wss:// through a tunnel that closes connections it sees idle. With no one watching, the link carried nothing, so the tunnel cut it every two minutes. Each time the edge redialled within two seconds: the edge's journal showed an end-and-reopen pair every ~126 s, and the home relay logged a new hop link at each one.

The change: each end of a WebSocket session (relay accepting, or relay dialling an upstream) sends a WebSocket ping (RFC 6455 §5.5.2) every 30 s while the session lasts. The peer's WebSocket answers with a pong, so a front between them sees traffic both ways. The MOQT session is unaffected: the receiver already ignored non-binary messages, and the library answers pings.

  • transport/websocket.rs: PING_EVERY (30 s); session pings at it, and session_pinging takes the interval. The sender is shared with the ping task, which holds only a weak reference, so the pings stop when the session's sender is dropped or a ping cannot be sent.
  • README.md: the binding gains step 8, "Keeping alive".

Checks (Framework box):

  • cargo test --locked -p joule-moq-relay: every test passes, including the new an_idle_session_pings_its_peer (three pings at a 50 ms interval).
  • Falsified: with the ping loop's tick replaced by break, the new test fails ("0 arrived"); restored.
  • cargo clippy -p joule-moq-relay --all-targets --no-deps -D warnings: nothing in the changed files. The host's newer clippy flags server.rs:182 (a large Err variant), which this change does not touch; CI's pinned clippy passes it on main.
  • The public-name, comparative-prose and vanity-metric checks are clean.

Deploy note: the edge (ash-1) needs the rebuilt relay for the pings on its upstream link; the home relay gains them for the sessions it accepts.

🤖 Generated with Claude Code

The edge relay's link to its home relay runs over `wss://` through a tunnel that closes connections it sees idle. With no one watching, the link carried nothing, so the tunnel cut it every two minutes. Each time the edge redialled within two seconds: the edge's journal showed an end-and-reopen pair every ~126 s, and the home relay logged a new hop link at each one. **The change:** each end of a WebSocket session (relay accepting, or relay dialling an upstream) sends a WebSocket ping (RFC 6455 §5.5.2) every 30 s while the session lasts. The peer's WebSocket answers with a pong, so a front between them sees traffic both ways. The MOQT session is unaffected: the receiver already ignored non-binary messages, and the library answers pings. - `transport/websocket.rs`: `PING_EVERY` (30 s); `session` pings at it, and `session_pinging` takes the interval. The sender is shared with the ping task, which holds only a weak reference, so the pings stop when the session's sender is dropped or a ping cannot be sent. - `README.md`: the binding gains step 8, "Keeping alive". **Checks (Framework box):** - `cargo test --locked -p joule-moq-relay`: every test passes, including the new `an_idle_session_pings_its_peer` (three pings at a 50 ms interval). - **Falsified:** with the ping loop's tick replaced by `break`, the new test fails ("0 arrived"); restored. - `cargo clippy -p joule-moq-relay --all-targets --no-deps -D warnings`: nothing in the changed files. The host's newer clippy flags `server.rs:182` (a large `Err` variant), which this change does not touch; CI's pinned clippy passes it on main. - The public-name, comparative-prose and vanity-metric checks are clean. **Deploy note:** the edge (ash-1) needs the rebuilt relay for the pings on its upstream link; the home relay gains them for the sessions it accepts. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
joule-moq-relay: each end of a WebSocket session pings the other every 30 s
All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 13s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 9s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 7s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 5s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 4s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 5s
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 3m32s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 3m35s
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (pull_request) Successful in 1m2s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 2m58s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 6m31s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 40s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 8m46s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 1m47s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 7m47s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 4m30s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 12m15s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 10m49s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 1m15s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 14m35s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 8m32s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 17m57s
372a3e953d
The edge relay's link to its upstream runs over wss through a tunnel that
closes a connection it sees idle. With no one watching, the link carried
nothing, and the tunnel cut it every two minutes; the edge redialled within
two seconds each time. Each end now sends a WebSocket ping (RFC 6455
§5.5.2) every 30 s while the session lasts, and the peer's WebSocket
answers with a pong. The binding's README gains the step.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!513
No description provided.