Skip to content

feat(broadcasting): WebSocket reliability — activity monitor, jitter, connection timeout#58

Merged
anilcancakir merged 4 commits intomasterfrom
feat/activity-monitor
Apr 9, 2026
Merged

feat(broadcasting): WebSocket reliability — activity monitor, jitter, connection timeout#58
anilcancakir merged 4 commits intomasterfrom
feat/activity-monitor

Conversation

@anilcancakir
Copy link
Copy Markdown
Contributor

@anilcancakir anilcancakir commented Apr 9, 2026

Summary

Three broadcasting reliability improvements for ReverbBroadcastDriver:

Closes #55, closes #56, closes #57

Changes

Activity Monitor (#55)

  • reverb_broadcast_driver.dart_activityTimer, _pongTimer fields, _resetActivityTimer() / _cancelActivityTimers() methods, wired into _onMessage(), _handleConnectionEstablished(), disconnect(), _onDone()
  • 5 new test cases (ping after silence, pong timeout reconnect, timer reset on message, cancel on disconnect, restart after reconnect)

Reconnection Jitter (#56)

  • reverb_broadcast_driver.dartbackoffDelay() formula updated to base * (1 + random(0..0.3)), Random DI via constructor
  • Tests updated from exact equality to range matchers + seeded Random for determinism

Connection Timeout (#57)

  • reverb_broadcast_driver.dartconnect() uses .timeout() with configurable connection_timeout (default 15s), schedules reconnect on timeout
  • config/broadcasting.dart — Added connection_timeout: 15 default
  • 2 new test cases (throws TimeoutException, schedules reconnect after timeout)

Docs & Config

  • doc/digging-deeper/broadcasting.md — Connection Health Monitoring section, jitter formula, connection_timeout config
  • CHANGELOG.md — 3 feature entries under [Unreleased]
  • .claude/rules/broadcasting.md — Updated config example

Test plan

  • flutter test — 922 tests pass (914 existing + 8 new)
  • dart analyze — zero issues
  • dart format --set-exit-if-changed . — zero changes

…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.
Copilot AI review requested due to automatic review settings April 9, 2026 13:33
@sentry
Copy link
Copy Markdown

sentry bot commented Apr 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 (send pusher:ping after activity_timeout silence; close socket if no pusher:pong within 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.
@anilcancakir anilcancakir changed the title feat(broadcasting): add client-side activity monitor with ping/pong timeout feat(broadcasting): WebSocket reliability — activity monitor, jitter, connection timeout Apr 9, 2026
@anilcancakir anilcancakir requested a review from Copilot April 9, 2026 14:02
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 (no break/return/throw), which in Dart is a compile-time error and/or will cause unintended fall-through (e.g., handling pusher:connection_established would also run the pusher:ping path and others). Add explicit termination for each case (or use switch expressions) 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
@anilcancakir anilcancakir merged commit 5dfffca into master Apr 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants