Skip to content

docs(api): delegate rate limiting to the edge (ADR-0013) - #148

Merged
tiana-code merged 1 commit into
mainfrom
feat/E-01-rate-limiting-edge
Jun 16, 2026
Merged

docs(api): delegate rate limiting to the edge (ADR-0013)#148
tiana-code merged 1 commit into
mainfrom
feat/E-01-rate-limiting-edge

Conversation

@tiana-code

Copy link
Copy Markdown
Owner

Decision

Resolves issue #52 by delegating rate limiting to the API gateway / edge, not implementing it in the ledger. Records the decision in ADR-0013 and annotates api/openapi.yaml so the enforcer is unambiguous.

Why delegate (not implement in-service)

  • Correctness under horizontal scaling is the decisive argument. PR feat(infra): add ledger helm chart with lint and kubeconform ci #147 (Add Helm templates ledger-* #68) shipped an HPA scaling the stateless ledger to 10 replicas. Per-replica in-memory counters are not global: a local 100/sec per-IP cap across 10 replicas becomes an effective ~1000/sec global cap (10x looser than advertised, and it drifts with the replica count). A correct in-service limiter would require a shared store (Redis) + trusted X-Forwarded-For extraction, i.e. a stateful dependency bolted onto a deliberately stateless service.
  • Separation of concerns / right layer. The platform architecture already assigns auth, rate limit, and routing to a future gateway service. The edge already holds the trusted client IP and the JWT subject; a token bucket there is a config line, not a new subsystem.

What changes

  • Committed: api/openapi.yaml - the ## Rate limiting description and the TooManyRequests response now state enforcement is at the gateway / edge. The 429 + Retry-After contract and the 100/sec / 1000/sec targets are unchanged (clients still receive 429 from the edge).
  • No code added: no in-service rate-limit filter, config, or dependency (Redis/bucket4j/resilience4j). The ledger stays stateless.

ADR-0013 (staged for Wiki)

The decision record ADR-0013-Rate-Limiting-At-The-Edge.md (decision, rationale, preserved targets, vendor-neutral reference gateway config - Spring Cloud Gateway RequestRateLimiter + Redis, with NGINX/Envoy/Kong equivalents, consequences, alternatives) is prepared under wiki/ (gitignored per the docs-in-Wiki convention) and the ADR-Index row added, for the owner to publish to the GitHub Wiki. It is not part of this git diff.

Verification

Description-only spec change; OpenApiContractIT compares path keys, so the contract test is unaffected (no path or schema key added/removed). Gate chain: analyst (decided the path with rationale), writer (ADR-0013 draft).

Closes #52

The OpenAPI advertised per-IP and per-user rate limits with a 429 plus
Retry-After, but no ledger code enforced them and the ledger is stateless and
scaled to 10 replicas by the HPA, so per-replica counters cannot enforce a
global limit. Records the decision (ADR-0013) to enforce rate limiting at the
API gateway / edge and annotates the spec so the enforcer is unambiguous. The
429 contract and the 100/sec and 1000/sec targets are unchanged; no in-service
rate-limiting code or dependency is added.

Closes #52
@tiana-code
tiana-code merged commit b86ce95 into main Jun 16, 2026
8 checks passed
@tiana-code
tiana-code deleted the feat/E-01-rate-limiting-edge branch June 16, 2026 18:01
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.

Rate limiting (429 + Retry-After) or ADR delegating it to the gateway

1 participant