Rate Limiter
Bound accepted throughput to protect downstream — the contractual complement of reactive back-pressure.
Problem
A misconfigured EDI partner pushes 50,000 INVOIC in two minutes because their producer has a bug. If the hub accepts, downstream (ERP, archive, audit) drowns for hours. If the hub silently drops, invoices are lost. The right answer is in between: refuse above a contractual throughput, explicitly notify the partner and steer them back to the agreed rate.
Forces
- Partner SLAs are contractual. A partner subscribed to 1,000 INVOIC/day. 50,000 in two minutes is a violation.
- Downstream has finite capacity. No magic: beyond, latency explodes.
- Legitimate spikes exist. Month-end, quarter-end — must absorb without breaking everything.
- Refusal must be explicit. HTTP 429,
Retry-After, operational contact — not silence.
Solution
Implement a counter per identification key (partner, IP, API token),
incremented on each message received and decremented per algorithm
(typically token bucket or leaky bucket). Beyond the threshold,
refuse with an explicit code — HTTP 429 Too Many Requests
+ Retry-After, 503 Service Unavailable, or
an application-level error code on AS2/AS4. The partner is notified,
can retry, and the partner account manager can be alerted of unusual
volume.
EDI implementation
Concrete case: the API gateway (Kong, AWS API Gateway, Cloudflare)
applies a quota per partnerId. The AS2 connector returns
a negative MDN beyond the contractual throughput. Native Kafka quotas
(producer-byte-rate, consumer-byte-rate)
limit per client ID. On the REST API exposed to partners, the limit
(1,000 msg/day) is documented in the technical contract and
enforced at the ingress. Walmart, Stellantis and OpenPEPPOL all
impose throughput contracts in their partner agreements.
Algorithms
- Token bucket: a bucket of N tokens, refilled at R tokens/second. Each request consumes 1 token. Beyond, refuse. Dominant algorithm — allows controlled bursts.
- Leaky bucket: requests enter a queue, leave at a constant rate. Bursts absorbed but smoothed. Stricter, ideal to pace a rigid downstream.
- Fixed window: N counter per window (per minute, per hour). Simple but prone to edge-of-window bursts.
- Sliding window log: timestamp log, count on the sliding window. Precise but expensive.
Anti-patterns
- No rate limit. A misconfigured partner breaks everyone else's production.
- Single global limit. No per-partner quota = a chatty partner consumes the shared quota.
- Silent refusal. Drop without 429 response — the sender does not understand what is going on.
- Limit too low for legitimate spikes. The partner is blocked at month-end on normal business volumes. Document the negotiated quota.
- Limit too high. Ineffective: it does not protect actual downstream. Measure real capacity and tune from there.
Related patterns
- Back-pressure — reactive downstream→upstream regulation, complementary.
- Bulkhead — compartment isolation, often paired with a per-compartment rate limit.
- Circuit Breaker — abrupt cut-off when downstream fails, to combine with the rate limiter.
Sources
- RFC 2697 — A Single Rate Three Color Marker (Heinanen J., Guerin R., IETF 1999). Reference specification of token bucket. rfc-editor.org/rfc/rfc2697
- RFC 6585 §4 — HTTP 429 Too Many Requests (Nottingham M., IETF 2012). rfc-editor.org/rfc/rfc6585
- Stripe — Rate limiters in production. stripe.com/blog/rate-limiters
- AWS Builders Library — Using load shedding to avoid overload. aws.amazon.com/builders-library
- Apache Kafka — Quotas. Native quotas per client ID (producer/consumer byte rate). kafka.apache.org/documentation/#quotas