Skip to content

sliding window + token bucket adapters - #121

Merged
abnegate merged 23 commits into
mainfrom
strategy/sliding-window
Aug 13, 2026
Merged

sliding window + token bucket adapters#121
abnegate merged 23 commits into
mainfrom
strategy/sliding-window

Conversation

@ArnabChatterjee20k

Copy link
Copy Markdown
Contributor

No description provided.

@@ -0,0 +1,217 @@
<?php

@ArnabChatterjee20k ArnabChatterjee20k Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all redis adapters are sharing the same code. So created this base similar to the sql base pattern in database with helper functions in each specific adapter

@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds Redis-backed sliding-window and token-bucket rate-limiting strategies with shared implementations for standalone, clustered, and pooled Redis connections.

  • Performs atomic enforcement through Lua scripts.
  • Recomputes sliding-window state from the live clock and reads fresh weighted counts.
  • Validates sliding-window and token-bucket configuration.
  • Adds shared integration tests for Redis, Redis Cluster, and Redis Pool adapters.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/Abuse/Adapters/SlidingWindow/RedisBase.php Implements live window calculation, weighted two-bucket enforcement, sufficient bucket retention, and reset behavior; the previously reported defects are corrected.
src/Abuse/Adapters/SlidingWindow/None.php Adds a no-op sliding-window adapter and now rejects non-positive window sizes before modulo arithmetic.
src/Abuse/Adapters/SlidingWindow.php Defines the common sliding-window contract, including remaining-count and reset operations.
src/Abuse/Adapters/TokenBucket/RedisBase.php Implements atomic refill-and-consume behavior and fresh read-only token estimates through Redis Lua scripts.
tests/Abuse/SlidingWindow/Base.php Exercises limiting, remaining capacity, expiry, reset, TTL validation, dynamic keys, and unlimited operation across Redis adapters.
tests/Abuse/TokenBucket/Base.php Provides shared behavioral coverage for the new token-bucket adapters.

Fix All in Greploop

Reviews (6): Last reviewed commit: "Merge pull request #122 from utopia-php/..." | Re-trigger Greptile

Comment thread src/Abuse/Adapters/SlidingWindow/RedisBase.php Outdated
Comment thread src/Abuse/Adapters/SlidingWindow/RedisBase.php Outdated
Comment thread src/Abuse/Adapters/SlidingWindow/RedisBase.php Outdated
Comment thread src/Abuse/Adapters/SlidingWindow/RedisBase.php Outdated
…timate

- reject windowSize <= 0 to avoid DivisionByZeroError
- require ttl >= 2*windowSize so the previous bucket outlives the current window
- return and cache the weighted estimate so remaining() stays consistent with check()
Introduce the storage-agnostic TokenBucket adapter (mirrors SlidingWindow:
count()/remaining()/limit()/time()) and RedisBase, which owns the atomic
refill-and-consume Lua script, a read-only refill estimate and the
eval()/delete() seams. Bucket state is a single Redis hash; ttl is derived
from capacity/refillRate.
Concrete adapters implementing the eval()/delete() seams plus getLogs()
(reads bucket hashes via hGetAll). Constructor takes (key, tokens, refillRate).
Shared Base suite covering burst/capacity, remaining, refill over time,
reset, refill-rate guard and unlimited (tokens 0).
…ount

Fractional refill made floor(capacity - balance) undercount consumed tokens
by one (e.g. balance 1.00001 -> 1 consumed instead of 2). Floor the available
balance first, then subtract from capacity so remaining() stays exact.
The bucket refills continuously, so caching the consumed count made
remaining() report a stale quota once time elapsed after a check(). Drop the
cache and compute a fresh estimate on every count(); check() now only needs
the allow decision.
…logs

Stopping each master's unordered scan at offset+limit and then sorting/slicing
the partial candidate set returned a biased page and could omit keys in range.
Scan all masters completely, then sort and slice.
Comment thread src/Abuse/Adapters/SlidingWindow/RedisBase.php Outdated
Comment thread src/Abuse/Adapters/SlidingWindow/None.php
@abnegate
abnegate merged commit 821a188 into main Aug 13, 2026
6 checks passed
@abnegate
abnegate deleted the strategy/sliding-window branch August 13, 2026 11:44
@ArnabChatterjee20k ArnabChatterjee20k changed the title Strategy/sliding window sliding window + token bucket adapters Aug 13, 2026
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.

2 participants