Blog

Why Our Rate Limiter Fails Open

September 5, 2026Xerat022 min read
Share

Every request to a public mock passes through a rate limiter before it reaches your routes. It's backed by Redis. And when Redis is unreachable, MockBase doesn't block the request — it lets it through. That's not an oversight; it's the deliberate design.

How the limiter works

It's a fixed-window counter, not a sliding-window or token-bucket scheme. For each caller, the current window is computed from wall-clock time (now - (now % window)), and the Redis key embeds that window boundary directly: ratelimit:{namespace}:{identifier}:{window_start}. There's no cleanup job — a key that isn't touched again simply expires on its own.

A single check does two things in one round trip:

INCR ratelimit:engine:<identifier>:<window_start>
EXPIRE ratelimit:engine:<identifier>:<window_start> <window_seconds>

Both commands are pipelined (redis.pipeline(transaction=True)), so a rate-limit check costs one network round trip, not two, on every single request to the mock engine. Namespaces keep buckets independent — the public mock engine (engine, 120 requests per 60-second window by default) and the authenticated management API (60 requests per 60-second window) never share a counter, so heavy traffic on one can't burn through the other's allowance.

The failure mode that actually matters

Here's the part that's easy to get backwards: what happens when the INCR/EXPIRE pipeline throws — Redis is down, a network blip, a timeout?

The limiter catches the exception and returns "allowed," full remaining quota, no retry-after. In other words: on any Redis error, every request passes.

That's the opposite of what a lot of rate limiters do by default, and it's a real tradeoff, not a free lunch. A "fail closed" limiter — reject everything when the backend is unreachable — protects you from abuse during an outage but takes down every mock the moment Redis has a bad five minutes. For an internal admin API, fail-closed is often the right call. For a public mock engine that other people's CI pipelines and demos depend on, an outage in the rate limiter taking down the entire product is a worse failure than temporarily having no rate limiting at all.

So the priority order here is explicit: availability of the mock engine beats strict enforcement of the limit. Rate limiting is a defense against accidental floods and casual abuse, not the last line of defense against a determined attacker — and it's not worth sacrificing uptime for every legitimate caller to enforce it perfectly during a Redis blip.

The tradeoff, stated plainly

This means a sustained Redis outage is technically a window where rate limits don't apply at all. MockBase accepts that risk deliberately: a rare, temporary loss of one abuse-prevention layer is a better failure mode than an infrastructure hiccup in a side dependency taking the whole mock engine offline for every user.

X

Xerat02

Building MockBase.