fix(usage_limit): atomic usage limit enforcement across concurrent requests#463
fix(usage_limit): atomic usage limit enforcement across concurrent requests#463raushan728 wants to merge 2 commits into
Conversation
Greptile SummaryThis PR replaces the old read-then-increment two-phase approach in
Confidence Score: 4/5Safe to merge for single-rule deployments; multi-rule configurations will experience a documented quota leak under concurrent load that is tracked as a follow-up. The atomic check_and_increment correctly enforces limits within a single rule under concurrent load, which is the primary goal of this fix. The multi-rule quota-leak (earlier rules permanently increment before a later rule denies) is a real behaviour change from the old two-phase approach, but the team has acknowledged it and explicitly documented it in the doc-comment and the test. The u32::MAX overflow guard is present. No new correctness issues were found beyond what is already tracked. crates/lib/src/usage_limit/usage_tracker.rs — the sequential check_and_increment loop for multi-rule configs warrants a second look once rollback support is available as a follow-up. Important Files Changed
Sequence DiagramsequenceDiagram
participant R as Request
participant T as UsageTracker
participant S as UsageStore
R->>T: check_and_record(ctx)
note over T: Phase 1 — pre-check (non-atomic)
loop For each rule
T->>S: get(key)
S-->>T: current count
alt "current + delta > max"
T-->>R: Denied (no counters touched)
else passes
T->>T: push to pending_increments
end
end
note over T: Phase 2 — atomic increment per rule
loop For each pending rule
T->>S: check_and_increment(key, delta, max, expiry)
note over S: Redis: Lua GET→compare→INCRBY→EXPIREAT
S-->>T: allowed (bool)
alt denied (concurrent race)
T-->>R: Denied — earlier rules already incremented
else allowed
T->>T: continue
end
end
T-->>R: Allowed
Reviews (10): Last reviewed commit: "chore(usage_limit): refine comments and ..." | Re-trigger Greptile |
69fea37 to
7536a5b
Compare
|
This PR has been inactive for 7 days and has been marked as stale. It will be closed in 5 days if there is no further activity. |
605aac3 to
2dc86e4
Compare
|
This PR has been inactive for 7 days and has been marked as stale. It will be closed in 5 days if there is no further activity. |
2dc86e4 to
b197dd4
Compare
|
This PR has been inactive for 7 days and has been marked as stale. It will be closed in 5 days if there is no further activity. |
|
Just keeping this PR active |
Replaces read-then-increment with atomic check_and_increment Mutex for in-memory, Lua script for Redis. TTL only set on first increment within a window. Denied requests may still consume quota from earlier rules under concurrent load.
b197dd4 to
e624358
Compare
The usage limiter was doing a read-then-increment in two separate steps, so concurrent requests could both pass the limit check before either one incremented.
Added
check_and_incrementto the store trait single mutex lock for in-memory, Lua script for Redis. Pre-checks all rules before incrementing; denied requests may still consume quota from earlier rules under concurrent load. TTL only set on first increment within a window.