Skip to content

Add :fix_window_per_key algorithm for ETS and Atomic backends#183

Merged
epinault merged 3 commits into
masterfrom
feature/fix-window-per-key
May 18, 2026
Merged

Add :fix_window_per_key algorithm for ETS and Atomic backends#183
epinault merged 3 commits into
masterfrom
feature/fix-window-per-key

Conversation

@epinault

Copy link
Copy Markdown
Contributor

Closes #181.

Summary

Adds :fix_window_per_key to both the ETS and Atomic backends. It's a fixed-window variant whose window is anchored
to each key's first hit instead of a globally-aligned wall-clock epoch (multiples of scale since Unix epoch,
like :fix_window uses today).

Same one-entry-per-key memory profile as :fix_window. The 2× boundary burst is still theoretically possible per
key, but boundaries are no longer globally synchronized — they can't be timed deterministically by an attacker, and
a key has to wait a full scale between burst opportunities. Same semantics as the common Redis INCR + EXPIRE NX
pattern.

Naming chosen deliberately over :rolling_window — the algorithm is mechanically a fixed window, just with a
per-key epoch. The docstring is explicit that the 2× burst is still possible, so users reaching for this won't
expect :sliding_window-level precision.

What's included

  • Hammer.ETS.FixWindowPerKey and Hammer.Atomic.FixWindowPerKey
  • Dispatch wiring in Hammer.ETS and Hammer.Atomic (incl. before_clean algorithm name)
  • Atomic backend reuses the existing clean_fix_window path (identical row layout)
  • Test files mirroring the existing fix_window tests, plus distinguishing tests for per-key window anchoring,
    expiry behavior, and the atomic race condition
  • before_clean callback tests in both clean_test.exs files
  • README algorithm table, comparison section, and selection guide updated
  • CHANGELOG ## Unreleased entry

Test plan

  • mix test — 129/129 passing
  • mix credo --strict — clean
  • mix format --check-formatted — clean

A fixed-window variant whose window is anchored to each key's first hit
instead of a globally-aligned wall-clock epoch. Keeps the same
one-entry-per-key memory profile as :fix_window. The 2x boundary burst
is still possible per key, but boundaries are no longer globally
synchronized, so they cannot be exploited deterministically. Same
semantics as the common Redis INCR + EXPIRE NX pattern.

Closes #181.
vittorio-reinaudo and others added 2 commits May 14, 2026 15:45
- Add allow_or_deny/3 to ETS and Atomic FixWindowPerKey backends
- Extract do_inc/4 in Atomic backend, mirroring do_hit/5
@epinault epinault merged commit 583e43f into master May 18, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rolling window algorithm

2 participants