Give the quota a sense of time and it becomes the most common real limiter - the fixed-window counter. It divides time into aligned windows and resets the count at the start of each one, so a client gets a fresh allowance every window.
Reset the count whenever the clock crosses into a new fixed window.
A fixed-window counter slices time into equal windows aligned to the clock -
with a window of 10 ticks, window 0 covers ticks [0, 10), window 1 covers
[10, 20), and so on. The window a tick belongs to is just now / window under
integer division. Inside a window it behaves exactly like yesterday’s quota: allow
while count < limit, deny once the limit is hit. The new idea is the reset:
the moment a request arrives in a window index different from the one we last saw,
zero the count before deciding.
This is the limiter most APIs reach for first because it is trivial to store - one count and one window index per client. Windows are aligned to the clock, not to each client’s first request, so every client’s allowance flips over at the same ticks (10, 20, 30). Pin the reset exactly: at limit 3 the requests at ticks 0, 1, 2 exhaust window 0, ticks 3 through 9 are denied, and tick 10 opens window 1 with a clean count. Tomorrow you expose how much of the current window’s allowance is left.
type FixedWindow struct {limit, window int64count int64curWindow int64}func (f *FixedWindow) Allow(now int64) Decision {w := now / f.window // which aligned window are we in?if w != f.curWindow { // crossed into a new window: resetf.curWindow = wf.count = 0}// then the familiar count < limit test}