Skip to content

fix: refresh redis-quota concurrency TTL to prevent over-admission (#335) - #336

Merged
jtechapps merged 2 commits into
llm-d:mainfrom
shimib:fix/quota-concurrency-ttl-refresh
Jul 23, 2026
Merged

fix: refresh redis-quota concurrency TTL to prevent over-admission (#335)#336
jtechapps merged 2 commits into
llm-d:mainfrom
shimib:fix/quota-concurrency-ttl-refresh

Conversation

@shimib

@shimib shimib commented Jul 21, 2026

Copy link
Copy Markdown
Member

What / why

Fixes #335 (sibling of #311/#334). In RedisQuotaGate concurrency mode (pkg/redis/quota_gate.go), the in-flight counter's EXPIRE was set only on the first acquire (new_val == 1) and never refreshed. The TTL = window (factory default 1m; multitenant overlays don't set it), so under sustained per-tenant load the key expires mid-flight, the counter resets to 0, and further requests are admitted beyond limit — recurring every window, and for any request in flight longer than window.

This is the correctness residual after #334: that PR made the counter accurate (retries no longer leak INCRs), but an accurate-but-positive counter was still wiped by the TTL.

Changes (pkg/redis/quota_gate.go, acquireConcurrency)

  • Refresh EXPIRE on every acquire (drop the new_val == 1 guard) — the counter can't expire while there's activity; the key now expires only after window of total inactivity (crash-orphan cleanup).
  • Refresh EXPIRE on release while reservations remain in flight.
  • Regression test TestRedisQuotaGate_Concurrency_TTLRefresh (TTL refresh across interleaved acquires via miniredis FastForward) — fails on main, passes with the fix.

Rate-limit mode is unchanged (its sorted set expires per-member correctly).

Testing

  • go test ./pkg/redis/... green (new + existing quota tests).
  • Regression test verified to fail on main and pass with the fix.
  • (The unrelated producer.TestMultipleTenantsIsolation flake is pre-existing and in a different, untouched module.)

Closes #335

…lm-d#335)

Concurrency-mode redis-quota tracks in-flight requests as an INCR/DECR
counter, but set the key's EXPIRE only on the first acquire (new_val==1)
and never refreshed it. The TTL equals window (factory default 1m; the
multitenant overlays don't set it). Under sustained per-tenant load the
counter stays positive, so ~window seconds after it first went positive
the key expires mid-flight, the counter resets to 0, and further requests
are admitted beyond the limit -- over-admission up to 'limit' extra
concurrent per tenant, recurring every window (and for any request in
flight longer than window).

This is the correctness residual after llm-d#311/llm-d#334: llm-d#334 made the counter
accurate (retries no longer leak INCRs), but an accurate-but-positive
counter was still wiped by the TTL.

- Refresh EXPIRE on every acquire so the counter cannot expire while there
  is activity; the key now expires only after window of total inactivity
  (crash-orphan cleanup).
- Refresh EXPIRE on release while reservations remain in flight.
- Add a regression test (TTL refresh across interleaved acquires) that
  fails before this change and passes after.

Rate-limit mode is unchanged (its sorted set expires per-member correctly).

Closes llm-d#335

Signed-off-by: Shimi Bandiel <shimib@google.com>
…-admission fix)

Signed-off-by: Shimi Bandiel <shimib@google.com>
Comment thread pkg/redis/quota_gate.go
@jtechapps
jtechapps merged commit 0eae977 into llm-d:main Jul 23, 2026
8 checks passed
This was referenced Jul 23, 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.

Concurrency-mode redis-quota over-admits when the counter TTL expires mid-flight

2 participants