Home/Low-level design/Rate Limiter

Rate Limiter

Per-client sliding windows and explicit time

A sliding window owns accepted timestamps and an observed clock separately. Denials add no accepted event but still advance observed time. Therefore checking time only against the last accepted request misses regressions after a denial.

go
now, window := 10, 4
acceptedAt := 6
fmt.Println(acceptedAt > now-window) // false: exact left boundary expired

Each client has an independent clock and budget. Reading history must not advance or expire anything; only a valid allow call does so. Explicit logical time makes tests deterministic and exposes boundary behavior without sleeping. This model is a strict sliding count window, unlike fixed windows or token buckets.

Go models this service with a struct and pointer-receiver methods. Constructor functions return a pointer; validation failures return errors rather than panicking. Scalars in snapshot structs are copied by value. Maps, slices, and optional pointers still require detached copies when crossing the service boundary. Go maps do not have key iteration order; use ordered slices for ranked results. There are no threads, persistence, wall-clock reads, or external side effects in this exercise.

Put it into practice

Implement the exercise in a full-screen workspace, then run its tests.

Open practice
Next lessonBanking System