fix(observability-proxy): keep Retry-After positive at tiny rates

The wait until the next token was converted from float to Duration
without a range check, so a rate limit below about 1e-10 requests per
second produced a negative Retry-After on amd64. The wait now saturates
at the largest Duration.

The earlier 429 change said range, step, bucket and limit violations
keep 422; on the logs root they are clamped or answer 400, and nothing
answers 422.

Assisted-by: LLM
Signed-off-by: ZverGuy <maximbel2003@gmail.com>
This commit is contained in:
ZverGuy committed 2026-11-10 00:45:06 +07:00
1 parent 97a536b89a
commit f19363ec62
2 files changed
+14 -1

No files matched your search

+6 -1
View File
@@ -17,6 +17,7 @@ limitations under the License.
package observabilityproxy
import (
"math"
"sync"
"time"
)
@@ -79,7 +80,11 @@ func (l *limiter) allowRate(user string) (time.Duration, bool) {
b.tokens = min(burst, b.tokens+now.Sub(b.last).Seconds()*l.cfg.RatePerUser)
b.last = now
if b.tokens < 1 {
return time.Duration((1 - b.tokens) / l.cfg.RatePerUser * float64(time.Second)), false
wait, ok := scaleDuration((1-b.tokens)/l.cfg.RatePerUser, time.Second)
if !ok {
wait = math.MaxInt64
}
return wait, false
}
b.tokens--
return 0, true
@@ -108,3 +108,11 @@ func allowed(l *limiter, user string) bool {
_, ok := l.allowRate(user)
return ok
}
func TestLimiterRateWaitAtTinyRate(t *testing.T) {
l := newLimiter(LimiterConfig{RatePerUser: 1e-12, RateBurst: 1})
allowed(l, "alice")
if wait, ok := l.allowRate("alice"); ok || wait <= 0 {
t.Fatalf("empty bucket at a tiny rate: admitted %v, wait %s, want refused with a positive wait", ok, wait)
}
}