Skip to content

Add reconnect-with-backoff and missed-event recovery to the Activity SSE stream #258

Description

@Lakes41

Difficulty: Advanced
Type: Performance

Background
.env.example documents NEXT_PUBLIC_ACTIVITY_REFRESH_MS as an "Activity delivery fallback interval," describing automatic SSE with a polling fallback, and notes that setting it to 0 "disable[s] automatic SSE and polling while retaining manual refresh." This confirms the /activity page relies on a live SSE connection with polling as a secondary mechanism.

Problem
There's no documented or apparent handling for what happens when the SSE connection drops (network blip, server restart, proxy timeout): does the client silently stop receiving updates until a manual refresh, does it retry immediately in a tight loop, and are events that occurred during the disconnect window lost entirely? None of this is addressed by the simple polling-interval fallback alone.

Expected outcome
The activity feed client detects SSE disconnects, retries the connection using exponential backoff with jitter (capped at a sane maximum), and on reconnect, requests any activity events that occurred after the last event it successfully received (using a timestamp or event-id cursor) so no events are silently lost during a disconnect window shorter than the outage-recovery threshold.

Suggested implementation

  • Add a lastEventId/lastSeenTimestamp cursor tracked client-side (and ideally acknowledged server-side via SSE's native Last-Event-ID support).
  • Implement exponential backoff (e.g. 1s → 2s → 4s ... capped at 30s) with jitter for reconnect attempts.
  • On successful reconnect, call the existing paginated activity API (see Issue Add wallet address validation to the /verify command #1, if implemented) with an after=<cursor> parameter to backfill missed events before resuming the live stream.
  • Ensure the existing polling fallback interval still functions independently as the last line of defense if SSE is fully disabled (NEXT_PUBLIC_ACTIVITY_REFRESH_MS=0 should still allow manual refresh only, unchanged).

Acceptance criteria

  • Simulating an SSE disconnect (e.g. by having the mock endpoint close the connection) triggers a backoff-based reconnect rather than a tight retry loop or silent failure.
  • Events generated during a simulated disconnect window are backfilled once the client reconnects.
  • Existing polling-fallback behavior (NEXT_PUBLIC_ACTIVITY_REFRESH_MS) is unaffected for environments where SSE is disabled.
  • Reconnect attempts and backfill requests are covered by tests (using fake timers where appropriate).
  • pnpm --filter @guildpass/dashboard test and pnpm typecheck pass.

Likely affected files/directories
apps/dashboard/app/activity/, activity SSE route/handler (apps/dashboard/app/api/activity/** or equivalent), client-side activity feed hook/component.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSGrantFox Open Source Sponsorship program tagMaybe RewardedIssue may qualify for a reward upon successful completion per campaign rulesOfficial Campaign | FWC26Official FWC26 campaign issue — eligible for campaign scoring and rewardsdashboardAutomatically createdenhancementImprovement or extension to existing project functionality, architecture, or developer experiencehelp wantedExtra attention is neededperformancePerformance optimization or latency/throughput improvement work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions