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.

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 createdenhancementNew feature or requesthelp 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