feat(broadcasting): WebSocket reliability — activity monitor, jitter, connection timeout#58
Merged
anilcancakir merged 4 commits intomasterfrom Apr 9, 2026
Merged
Conversation
…imeout Implement Pusher protocol client-side activity monitoring in ReverbBroadcastDriver. After activity_timeout seconds of silence, sends pusher:ping and waits 30s for pusher:pong — reconnects if no response. Detects silent connection loss from server crashes, network partitions, and deployments without WebSocket close frames.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Adds Pusher-protocol client-side connection health monitoring to ReverbBroadcastDriver so silent WebSocket failures can be detected and recovered via ping/pong + reconnect.
Changes:
- Introduces activity monitoring timers in
ReverbBroadcastDriver(sendpusher:pingafteractivity_timeoutsilence; close socket if nopusher:pongwithin a timeout). - Adds test coverage for ping scheduling, pong-timeout closure behavior, timer reset/cancel, and post-reconnect restart.
- Documents the connection health monitoring behavior and records the feature in the changelog.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| lib/src/broadcasting/drivers/reverb_broadcast_driver.dart | Adds activity/pong timers and hooks them into message handling and lifecycle. |
| test/broadcasting/drivers/reverb_broadcast_driver_test.dart | Adds 5 new tests for the activity monitor behavior. |
| doc/digging-deeper/broadcasting.md | Documents the new connection health monitoring flow. |
| CHANGELOG.md | Notes the feature under Unreleased. |
Add random jitter of up to 30% to the exponential backoff formula. Prevents thundering herd when many clients reconnect simultaneously after a server restart. Inject Random via constructor for deterministic test behavior.
Add configurable timeout (default 15s) to connect() — prevents indefinite hang when server doesn't complete the Pusher handshake. On timeout, closes the socket and triggers the reconnect cycle. Configurable via connection_timeout in broadcasting config.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
lib/src/broadcasting/drivers/reverb_broadcast_driver.dart:442
- The
switch (event)cases don’t terminate (nobreak/return/throw), which in Dart is a compile-time error and/or will cause unintended fall-through (e.g., handlingpusher:connection_establishedwould also run thepusher:pingpath and others). Add explicit termination for each case (or useswitchexpressions) so only the intended handler runs.
_resetActivityTimer();
switch (event) {
case 'pusher:connection_established':
_handleConnectionEstablished(json);
case 'pusher:ping':
_sendPong();
case 'pusher:subscription_succeeded':
_handleSubscriptionSucceeded(json);
case 'pusher:error':
_handlePusherError(json);
case 'pusher_internal:member_added':
_handlePresenceEvent(json);
case 'pusher_internal:member_removed':
_handlePresenceEvent(json);
default:
_handleApplicationEvent(json);
}
- Cancel activity timers in _scheduleReconnect() to prevent stale timers firing on new socket after reconnect - Replace pow(2, attempt) with iterative doubling to prevent overflow on large attempt values - Use await expectLater for async timeout assertion - Rename test to match actual behavior (closes socket, not reconnects) - Clarify pongTimeout is configurable (30s default) in docs
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.
Summary
Three broadcasting reliability improvements for
ReverbBroadcastDriver:activity_timeout+pusher:ping/pusher:pong. Detects silent connection loss and triggers automatic reconnectionconnect()prevents indefinite hang when server doesn't complete handshakeCloses #55, closes #56, closes #57
Changes
Activity Monitor (#55)
reverb_broadcast_driver.dart—_activityTimer,_pongTimerfields,_resetActivityTimer()/_cancelActivityTimers()methods, wired into_onMessage(),_handleConnectionEstablished(),disconnect(),_onDone()Reconnection Jitter (#56)
reverb_broadcast_driver.dart—backoffDelay()formula updated tobase * (1 + random(0..0.3)),RandomDI via constructorConnection Timeout (#57)
reverb_broadcast_driver.dart—connect()uses.timeout()with configurableconnection_timeout(default 15s), schedules reconnect on timeoutconfig/broadcasting.dart— Addedconnection_timeout: 15defaultDocs & Config
doc/digging-deeper/broadcasting.md— Connection Health Monitoring section, jitter formula,connection_timeoutconfigCHANGELOG.md— 3 feature entries under [Unreleased].claude/rules/broadcasting.md— Updated config exampleTest plan
flutter test— 922 tests pass (914 existing + 8 new)dart analyze— zero issuesdart format --set-exit-if-changed .— zero changes