Skip to content

feat: add auto-reconnect with exponential backoff to admin webhook SSE stream (Closes #300) [fj4WqyCCw3C5ShR1RfB7MoBPTpkRrBFYP1uT35g3MvT] - #380

Open
waterWang wants to merge 1 commit into
Adamantine-guild:mainfrom
waterWang:feat/sse-reconnect-exponential-backoff
Open

feat: add auto-reconnect with exponential backoff to admin webhook SSE stream (Closes #300) [fj4WqyCCw3C5ShR1RfB7MoBPTpkRrBFYP1uT35g3MvT]#380
waterWang wants to merge 1 commit into
Adamantine-guild:mainfrom
waterWang:feat/sse-reconnect-exponential-backoff

Conversation

@waterWang

Copy link
Copy Markdown

Summary

Closes #300

Adds automatic reconnection with capped exponential backoff to the subscribeWebhookEvents() SSE stream in lib/api/live.ts.

Changes

Core reconnect logic (lib/api/live.ts)

  • Replaced the single fetch + .then() call with an async tryConnect() loop that auto-reconnects on failure
  • Added SSE-specific backoff constants (lazy functions for testability) with separate env vars:
    • NEXT_PUBLIC_SSE_RECONNECT_MAX_ATTEMPTS (default: 10)
    • NEXT_PUBLIC_SSE_RECONNECT_BASE_DELAY_MS (default: 100ms)
    • NEXT_PUBLIC_SSE_RECONNECT_MAX_DELAY_MS (default: 10s)
    • NEXT_PUBLIC_SSE_STABILITY_WINDOW_MS (default: 30s)
  • Added sseBackoffDelayMs() — capped exponential backoff with jitter (same pattern as REST backoffDelayMs)
  • Added onReconnecting callback parameter to notify callers of reconnect attempts
  • Backoff counter resets on successful connection, and after a stability window of successful frames
  • unsubscribe() now properly cleans up: sets stopped flag, clears pending reconnect timeout, aborts the controller

API surface (lib/api/types.ts, lib/api/mock.ts)

  • Added onReconnecting?: (attempt: number, delayMs: number) => void to the AdminAccessApi interface
  • Updated MockAccessApi to accept the new parameter (no-op)

Bug fixes

  • Fixed pre-existing syntax error in lib/wallet/connectors.ts (missing = [ in array literal)
  • Fixed pre-existing duplicate declaration in lib/api/mock.ts (duplicate analytics property)

Tests (test/webhook-stream-reconnect.test.ts)

  • 6 comprehensive tests using real timers (no mock timer issues):
    • Healthy stream delivers events without reconnecting
    • Dropped stream (reader done) triggers reconnect after backoff
    • HTTP error triggers reconnect after backoff
    • Unsubscribe stops all further reconnect attempts
    • Stops retrying after max attempts and gives up
    • onError is still invoked so polling fallback works

…vents (Adamantine-guild#300)

- Replace single fetch call with tryConnect loop that auto-reconnects
- Add SSE-specific backoff constants (lazy reads for testability)
- Add sseBackoffDelayMs() using capped exponential backoff with jitter
- Add onReconnecting callback to notify caller of reconnect attempts
- Reset backoff counter on successful connection
- Reset backoff after stability window of successful frames
- Clean up timeouts and abort controller on unsubscribe
- Add comprehensive test suite with node:test
- Fix pre-existing syntax errors in connectors.ts and mock.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add auto-reconnect with exponential backoff to the admin webhook SSE stream

1 participant