Skip to content

feat(api): raise the default per-IP rate limit to 600/min - #73

Merged
acedward merged 1 commit into
mainfrom
00043-rate-limit-shared-bucket
Sep 11, 2026
Merged

feat(api): raise the default per-IP rate limit to 600/min#73
acedward merged 1 commit into
mainfrom
00043-rate-limit-shared-bucket

Conversation

@acedward

Copy link
Copy Markdown
Contributor

Why

The 60/min default was sized for one polite browser tab. Measured on preprod (2026-09-09/10): an idle SPA tab uses 3 counted requests/min and an active trader 10–15/min, but the solver console polls 4 counted routes every 4 s (60/min) and the solver's settlement sweep plus a book page-through bursts to ~400/min, so any co-located automated client hit 429 RATE_LIMITED on its own.

What

  • API_RATE_LIMIT_MAX default 60 → 600 (packages/node/env.ts); deploy/ keeps its explicit 6000.
  • Docs now describe the real 429 body ({statusCode, error: "RATE_LIMITED", reason}) and the x-ratelimit-* headers instead of a shape the limiter never sent (API.md, README env table, FRONTEND-API-HANDOFF, deploy/.env.example).

Not breaking: deployments that set the variable are unaffected.

Companion

The per-user part of the fix is in the effectstream runtime (Fastify trustProxy): behind nginx every browser currently shares one bucket because request.ip is the proxy. Kernel main gets it via the midnight-1 port, ledger-v9 via v-next; ledger-v9 takes this PR by the usual main merge (PR #65 comment).

Tests

  • bun test packages/node/api-rate-limit.test.ts: 3 pass / 0 fail
  • bun run typecheck:backend: 0 diagnostics

The 60/min default was sized for one polite browser tab. Measured on
preprod: an idle SPA tab uses 3 counted requests/min and an active trader
10-15/min, but the solver console polls 4 counted routes every 4 s (60/min)
and the solver's settlement sweep plus a book page-through bursts to ~400/min,
so any co-located automated client hit 429 RATE_LIMITED on its own.

600/min covers a solver plus its console on one address with headroom; the
deploy scaffold keeps its explicit 6000. Docs now describe the real 429 body
(`{statusCode, error: RATE_LIMITED, reason}`) and the x-ratelimit-* headers
instead of a response shape the limiter never sent.
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