-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
Workload Resilience
-
ALL
-
WR Prioritized list
-
None
-
None
-
None
-
None
-
None
-
None
-
None
consumeOrDrain pre-checks balance > 0, then calls the storage-level consume with a min(available, toConsume) callback. If a concurrent borrow pushes zeroTime into the future between the check and the CAS (or between CAS retries), tokens goes negative inside the loop. The drain callback returns this negative value (the constexpr_min doesn't clamp at 0), consumed Unable to render embedded object: File (= 0}}, so {{tokensNew = 0}} and {{zeroTimeNew = now}}. This means the CAS erases all outstanding debt) not found. {{consumeOrDrain then returns a negative number, which the borrow loop treats as "nothing consumed" and borrows the full amount. The net effect is that the prior borrowers' debt is forgiven while they still sleep their full naps, and new arrivals are admitted against capacity that's already reserved.
*This is rare.* It needs balance near zero plus an interleaved borrow, but that's precisely the case where the limiter is actively limiting. The boolean consume() used by tryAcquireToken is safe (its callback returns 0 for insufficient balance). Only the drain callback can go negative. Clamping the callback at 0.0 fixes it.