(workspace, namespace, identifier, duration) tuple into a sliding-window decision. The normal path is local-memory first and reaches regional state when a counter is cold, stale, or in strict mode.
Single request flow
Each request builds two counter keys: the current fixed window cell and the previous fixed window cell. The previous cell is needed because the public behavior is a sliding window. The compare-and-swap loop protects the local counter from concurrent accepted requests in the same process. If another goroutine changes the current counter between the read and the commit, the request recomputes the effective count before trying again.Sliding-window math
The implementation stores fixed window cells, but the decision behaves like a sliding window. For a request at timet, the current sequence is:
1 at the beginning of a new fixed window and moves toward 0 as the current fixed window advances.
Counter entries
counterEntry is the in-memory state for one window cell. It is intentionally small because it sits on the request path.
The key invariant is that regional count and global count stay separate. Regional count can be published outward. Global count is imported from other regions and must not be published again.
Batch requests
RatelimitMany evaluates multiple limits with all-or-nothing semantics. The method temporarily increments each requested counter, evaluates the full batch, then either keeps every increment or rolls every increment back.
Global publishing reads regional count minus speculative count. That prevents temporary batch state from leaking into cross-region convergence before the batch is committed.