51Implement a token-bucket API rate limiter
Problem
A token bucket holds up to capacity tokens and refills continuously at refillPerSecond tokens per second. Every request spends tokens; a request without enough tokens must wait. This allows short bursts (up to capacity) while keeping the long-run rate at refillPerSecond.
Implement createTokenBucket({ capacity, refillPerSecond, now = Date.now }) returning:
tryRemove(count = 1): spendcounttokens and returntrueif there are enough, otherwise returnfalseand spend nothing.tokens(): the current number of tokens (may be fractional).msUntil(count = 1): how many milliseconds untilcounttokens will be available (0 if they already are).take(count = 1): an async version that waits until the tokens are available, then spends them.
The bucket starts full. now is injectable so time can be controlled in tests.
const limiter = createTokenBucket({ capacity: 10, refillPerSecond: 5 });
async function callApi(path) {
await limiter.take(); // at most 10 at once, then 5 per second
return fetch(path);
}Requirements
- Do not use a timer to refill; compute the refill from the elapsed time when you need it.
- Never exceed
capacity. tryRemovewithcount > capacityalways returnsfalse, andtakerejects with aRangeErrorfor it, because it could never succeed.
Try it yourself
Write your solution, run it, then submit to check it against the tests.
Press Run or ⌘ Enter to execute your code.
Step-by-step
Keep tokens (start at capacity) and last = now().
Unlock the full solution
What's inside
- Step-by-step
- Approach
- Solution
- Complexity
- Edge cases
- Follow-up questions
- Tests
Includes 2 code listings, 4 edge cases, 5 follow-up questions.
One-time payment by UPI, card or net banking. Launch price.