Skip to content

fix: respect relay 60s rate limit on GET /bundles#197

Merged
careck merged 4 commits into
masterfrom
fix/relay-rate-limit
May 10, 2026
Merged

fix: respect relay 60s rate limit on GET /bundles#197
careck merged 4 commits into
masterfrom
fix/relay-rate-limit

Conversation

@careck
Copy link
Copy Markdown
Member

@careck careck commented May 10, 2026

Summary

  • Stagger frontend polling hooks — both used 60s intervals firing simultaneously; now 120s each, offset by 60s so they alternate every 60s
  • Eliminate double list_bundles in identity polling — self-transfer discovery and invite polling each called list_bundles independently; now only one runs per identity per cycle
  • Downgrade 429 logs to debug — rate-limited polls are non-fatal and self-healing on the next cycle

Context

The relay added a per-account rate limiter (RateLimitMiddleware) enforcing 60s minimum between GET /bundles calls. The client was making multiple overlapping calls:

  1. useRelayPolling (workspace deltas) — immediate + every 60s
  2. useGlobalSnapshotPolling (identity snapshots) — immediate + every 60s
  3. Within identity polling: self-transfer discovery → list_bundles, then receive_poll_identity → list_bundles

All three could hit the same relay account within the same second, triggering 429.

Test plan

  • Open app with relay-connected workspace, verify no 429 warnings in logs
  • Verify workspace delta sync still works (deltas received within ~2 min)
  • Verify identity snapshot polling still works (invite acceptance flow)
  • Verify self-device transfer discovery still works (Send to My Device)
  • Check logs show alternating poll calls ~60s apart

careck added 4 commits May 10, 2026 14:16
The relay now enforces a per-account 60s minimum between list_bundles
calls (HTTP 429). Two independent React polling hooks both fired
immediately on mount and every 60s, causing overlapping requests.

- Increase both poll intervals from 60s to 120s (2x safety margin)
- Offset identity polling by 60s so the two alternate every 60s
- In poll_all_identity_snapshots, run either self-transfer discovery
  OR invite polling per identity (not both), since each calls
  list_bundles independently
- Downgrade 429 log from warn to debug (non-fatal, self-healing)
With the relay rate limit reduced from 60s to 15s per account,
restore the original 60s poll intervals (with 30s stagger).

- Parse Retry-After header from 429 responses into
  RelayRateLimited { message, retry_after_secs }
- Log retry_after_secs at debug level in poll commands
- Restore 60s intervals with 30s identity-poll offset
With the relay poll rate limiter removed from GET /bundles,
revert the client workarounds:
- Restore original 60s intervals with immediate first poll
- Restore both self-transfer discovery AND invite polling
  per cycle (no mutual exclusion)

Keep the Retry-After parsing in RelayRateLimited as defensive
code in case rate limiting is re-enabled in the future.
The delta builder's attachment size pre-scan logged a warn for
every AddAttachment op whose note was already deleted. This is
normal (op log is append-only) — downgrade to debug with a
clearer message explaining the blob is unavailable because the
note was likely deleted.
@careck careck merged commit c12349e into master May 10, 2026
1 of 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

Development

Successfully merging this pull request may close these issues.

1 participant