merge develop into developmod - #2
Merged
Merged
Conversation
Adds a read-timeout-by-ping mechanism to all of the websocket connections, with configurable ping interval and pong timeout. - Add 'ping_interval' and 'pong_wait' to device_listener and controller_listener config sections, with defaults (30s/30s) and validation. These are reloadable. Ping interval is how often to send a ping and pong_wait is the grace period added to interval for waiting for a pong. Read timeout is effectively ping interval + grace period. - Add 'registration_timeout' (duration, default 1m) to controller listener config section. This is reloadable. Used as the read deadline bounding the controller registration handshake, then reset to the normal ping-based timeout before the ping loop starts. Covers both v1 and v2 registration paths. - Expose device_listener/controller_listener ping settings (ping_interval, pong_wait, registration_timeout) via GET /api/config. - Update example config and API docs.
It's rotom-ng.toml, not rotom.toml
Global stats weren't accurate because they just added worker stats and workers come and go.
A CLI that connects simulated devices, workers, and controllers to a running RotomNG instance over the real WebSocket wire protocol, so the API and UI populate with live data instead of mocks. - Devices answer control commands; workers send a welcome message and echo SUCCESS responses; controllers register (v2), log in on their assigned worker, and send periodic RPC requests, forming the full controller -> rotom -> worker -> rotom -> controller pipeline. - CLI flags for device/worker/controller counts, endpoints, secrets, RPC interval, weight, etc. Validates controllers <= devices*workers when this connector supplies the workers. - Connections self-heal/reconnect; graceful shutdown on SIGINT/SIGTERM. - "gen-compose" subcommand writes a docker-compose.yml (rotom-ng built with DEV_MODE, a Vite dev-server sidecar for live UI from source, and the fleet) plus a matching dev config. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The device and controller handlers got ping-based read timeouts in d268b27, but the worker handler was missed, so a silent or hung MITM worker would hold its connection open indefinitely. Apply the same managed-ping-loop pattern to the worker handler: - Add WorkerHandlerSettings (ping_interval, pong_wait) with validation and a settings container, sourced from the device listener config since workers connect on the device listener. These are reloadable. - Install the read deadline and pong handler synchronously before the welcome handshake, then start the managed ping loop once registration succeeds (restarts on settings reload, exits on context cancel). - Wire worker handler settings through app Init and reload. - Note in docs/example config that the device_listener ping settings also govern worker connections. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Previously LastSeenAt only advanced on data messages (or sends), so a connection kept alive purely by ping/pong showed a stale last-seen timestamp. And even where the backend had it, the API only exposed last_seen_at_ms on devices/workers, while the UI ignored it entirely and recomputed "Last Seen" client-side from message timestamps. This affected all websocket connection types (devices, controllers, workers). ws stats: - Add ConnStats.LastPongAt, recorded by a new setPongReceived helper, and factor it into LastSeenAt(). Tracked separately from LastReceivedAt so pongs do not inflate the data-message counters. - Have the pong handler installed by EnableReadTimeout record the pong under statsMu. The handler runs on the read goroutine inside NextReader, which does not hold statsMu, so locking there is safe and keeps GetStats consistent. - ConnStats.Add now keeps the latest of each timestamp (via After) for all time fields rather than blindly overwriting, so a merge can never move a timestamp backward. A zero other still never clobbers an existing value. api: - Move LastSeenAtMs into CommonStats, populated from ws LastSeenAt(), so every connection type that embeds CommonStats (device, worker, controller, and the device/worker sessions) returns last_seen_at_ms. Remove the now-redundant per-struct LastSeenAtMs from Device and Worker. base-ui: - Use the API's last_seen_at_ms for the "Last Seen" column in the workers, controllers, and devices tables and in device-details, and sort by it directly. Drop the synthetic per-row last_seen fields and the now-unused getLastSeenTimestamp helper. - Mirror the type change (last_seen_at_ms on CommonStats) in the runtime and mock types, and populate it in controller and session mock data. Tests: - Unit tests for setPongReceived/Add/LastSeenAt and an end-to-end test that a received pong advances LastSeenAt without changing message counts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.