Stage 7 · Master
Caching and Rate Limiting
Rate Limiting with Redis
Meridian's rate limiter belongs at the gateway and must key every budget by tenant context, not by process-local memory alone.
Why the Gateway Owns It
The gateway is the only public entrypoint in Meridian, so it is also the only correct first place to enforce broad request budgets. identity-service, community-service, and billing-service should still be able to add narrow domain-specific limits later, but cross-cutting abuse protection belongs at the edge where a request first arrives. That keeps the internal services simpler and prevents one misbehaving client from consuming downstream capacity before the platform has a chance to reject it.
apps/gateway/internal/middleware currently contains only panic recovery. The rate-limiting middleware described in this lesson is a forward-looking design for that same package, not code that exists in the scaffold today.
What the Limit Keys On
| Traffic class | Suggested key | Reason |
|---|---|---|
| Unauthenticated public request | ip + host + path group | Tenant may not be resolved yet; basic abuse protection still needed |
| Authenticated tenant request | tenant_id + user_id + route group | Protects each tenant and actor budget separately |
| Tenant-wide burst budget | tenant_id + route group | Prevents one tenant from consuming the cluster unfairly |
| Webhook ingress to billing-service via gateway | tenant_id + provider + path group | Payment providers retry aggressively and need a dedicated envelope |
tenant_id must appear in the Redis key once the gateway has resolved the slug or authenticated the session. Without that, a large HOA tenant and a small HOA tenant could interfere with one another's budget, which is operationally incorrect even if the limiter still blocks some abuse. Multi-tenancy affects protective infrastructure as much as it affects SQL queries.
Workflow
Key: The gateway builds a Redis key from tenant scope plus actor or route details once identity is known.
Step 1 / 4 — Key
Redis-Backed Budgeting
gateway:ratelimit:ip:203.0.113.8:route:public-health
gateway:ratelimit:tenant:tenant_9f2a:actor:user_77:route:community-read
gateway:ratelimit:tenant:tenant_9f2a:route:billing-write
gateway:ratelimit:tenant:tenant_9f2a:provider:stripe:route:webhookThe public-IP key is the only form that omits tenant_id, because it applies before tenant resolution. Every tenant-aware route must graduate to a tenant-scoped key as early as possible in the request lifecycle.
Tenant Fairness
A rate limiter in a multi-tenant platform is not just a security control. It is also a fairness mechanism. One HOA tenant should not be able to saturate invoice-generation or complaint-search endpoints so aggressively that another tenant experiences elevated latency. The design therefore benefits from layered budgets: a small per-actor bucket nested under a larger per-tenant bucket, with route-group-specific capacities for reads, writes, and webhook traffic.
apps/gateway/internal/middleware/ratelimit.gocreateResponsibility: Extracts request identity, builds the tenant-aware Redis key, and blocks or forwards the request.
Why now: The gateway already owns the request middleware chain, so the limiter belongs there rather than in business handlers.
Connects to: Builds on apps/gateway/internal/middleware/middleware.go, which currently contains panic recovery only.
apps/gateway/internal/config/config.gomodifyResponsibility: Adds Redis address, password, and per-route budget settings to the gateway runtime configuration.
Why now: Rate limits should be configurable per environment without hard-coded constants.
Connects to: Extends the current config loader pattern that already reads downstream service URLs from the environment.
The Decision
- Rate limiting starts at the gateway because the gateway is the only public entrypoint.
- Redis is required once the gateway runs more than one pod; in-memory counters cannot enforce a shared budget.
- Every authenticated or resolved request should be limited by tenant_id, with optional actor and route-group dimensions layered on top.
- Unauthenticated public traffic may begin with IP-based keys, but tenant-aware keys should take over as soon as the gateway resolves context.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.