107Implement a distributed-style API client rate limiter coordinating multiple browser tabs
Problem
A third-party API allows 10 requests per minute per user. Your app may be open in five tabs, and each tab's own limiter thinks it has the full budget. Build a limiter whose budget is shared across tabs.
Implement createSharedRateLimiter({ name, limit, windowMs, storage, lock, now = Date.now, sleep }) returning:
tryAcquire():Promise<boolean>; take a slot if fewer thanlimitrequests were made by any tab in the lastwindowMs.retryAfter():Promise<number>; milliseconds until a slot frees (0 if one is free).acquire({ signal } = {}): wait (usingsleep(ms)) until a slot is free, then take it; reject withsignal.reasonif aborted.
Shared pieces are injected so the limiter works in browsers and in tests:
storage: asyncget(key)andset(key, value)(for example a thin wrapper overlocalStorageor IndexedDB). Keep the request timestamps as a JSON array under"ratelimit:{name}".lock(name, callback): runscallbackexclusively, like the Web Locks API (navigator.locks.request(name, callback)), and returns its result.
Requirement: every read-modify-write of the shared state must happen inside the lock. Without it, two tabs can read the same state at the same time and both take the last slot.
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
Every tab reads and writes the same key, "ratelimit:{name}", holding the timestamps of recent requests from all tabs. Storage is the "server" all tabs agree on.
Unlock the full solution
What's inside
- Step-by-step
- Approach
- Solution
- Complexity
- Edge cases
- Follow-up questions
- Tests
Includes 3 code listings, 5 edge cases, 4 follow-up questions.
One-time payment by UPI, card or net banking. Launch price.