What a limit protects
A rate limit isn't one idea. Every limit in a real application protects a different thing, and the thing it protects decides the algorithm, the number, and what the request is counted against.
This application has nine of them, in one file, and they aren't variations on a theme.
The nine
req/ip 300 per minute anonymous traffic, by IP
req/user 600 per minute signed-in traffic, by learner
logins/ip not published sign-in attempts, by IP
logins/email not published sign-in attempts, by email
signups/ip 3 per hour new accounts, by IP
comments/ip 10 per minute discussion posts, by IP
inquiries/ip 5 per hour partner inquiries, by IP
sandbox/user not published code runs, by learner
verdict_poll/user not published grading status checks, by learner
The sign-in and code-execution values are left out on purpose. Even so, look at the spread: from 600 per minute down to 3 per hour. That's a factor of twelve thousand, and it isn't carelessness. Each number comes from what would go wrong without it.
Four different protections
Capacity
req/ip at 300 per minute and req/user at 600 per minute protect the servers. Nothing about a single request is dangerous. The danger is volume, and both limits sit well above what a person browsing could produce. Anonymous traffic is counted per IP and signed-in traffic per learner, for a reason lesson 6 covers.
A secret
logins/ip and logins/email protect passwords from being guessed. Their limits are low because a handful of guesses is already generous: a real user who has forgotten their password uses the reset flow, not attempt after attempt.
A scarce resource
sandbox/user and verdict_poll/user protect the code-execution path, where each request costs far more than a page render. Both are counted per learner.
Something with a cost outside the system
signups/ip at 3 per hour and inquiries/ip at 5 per hour protect against junk that a person then has to deal with: accounts to clean up, inquiries to read.
flowchart TB
Q["what does this limit protect?"] --> C["capacity: the servers"]
Q --> S["a secret: passwords"]
Q --> R["a scarce resource: code execution"]
Q --> H["human time: signups, inquiries"]
C --> C1["300-600/min. generous, volume is the only danger"]
S --> S1["low. a handful of guesses is already generous"]
R --> R1["sized to the cost per request, counted per learner"]
H --> H1["3-5/hour. the cost lands on a person"]
The number follows the protection
No two of these limits could be swapped. Three logins per hour would lock out real users, and three hundred wouldn't slow an attacker down. The number isn't a knob you turn until the alerts stop. It's a statement about what a legitimate user does and what an attacker needs.
The fair way to pick one: describe the legitimate worst case, then leave headroom. A user mistyping a password does it three or four times, not fifty. A user signing up does it once, not eight times.
What a limit is not
A rate limit isn't a quota, and confusing the two causes real damage.
A quota is a budget over a long period, such as a thousand API calls a month. Running out is a normal, expected business event that the user planned around.
A rate limit is about the shape of traffic in the short term. Exceeding one signals that something is wrong right now, and the right response is to slow down and retry, not to buy more.
They fail differently and should be communicated differently. This application returns 429 Too Many Requests with "Please try again later". That sentence would actively mislead on a quota, because trying again later is the one thing that won't help.
Key takeaways
- This application has nine throttles, from 600 per minute to 3 per hour, and the spread is deliberate, not inconsistent.
- Limits protect four distinct things: capacity, a secret, a scarce resource, and people's time.
- The number follows the protection: describe the legitimate worst case, then leave headroom.
- A rate limit is about the shape of traffic now. A quota is a budget over a long period.
- Exceeding a limit means slow down and retry. Exceeding a quota means a retry won't help.
Keep going with lesson 2
The fixed window counter
How the fixed window counter puts the window number in the cache key and stays atomic in Solid Cache.
A free account also gives you the quizzes, your progress and notes, and the discussion.