feat(ratelimit): in-memory token bucket for pure-Pebble path#592
Merged
Conversation
The pure-Pebble path used a noopLimiter that allowed every request even when rate limits were configured. Silent foot-gun: operators saw the config knobs and trusted them; runtime ignored them. This commit ships an in-process token-bucket limiter for the pure-Pebble path. Each (scope, subject) pair gets its own bucket; refill uses real time, so the math matches the existing Redis Lua implementation. No external coordinator means per-NODE enforcement (cluster ceiling = N × bucket.RequestsPerMinute) — accepting that trade-off avoids dragging a Redis dep into the embedded path. Implementation: - internal/ratelimit/inmemory.go: InMemoryLimiter with sync.RWMutex over a buckets map; per-bucket sync.Mutex for the refill+decrement critical section. Janitor reaps buckets idle > 10 min so the map stays bounded under per-token churn. - pkg/app/application.go: when cfg.PersistenceProvider=="pebble", wire NewInMemoryLimiter() instead of the noopLimiter placeholder. Tests (8 passing): - Disabled bucket allows everything - BurstSize=3 + 4th call → blocked with RetryAfter ≥ 1s - After advancing the clock, tokens refill and allow again - Different subjects have independent buckets; different scopes with the same subject also independent - Capacity reconfigure clamps existing token count downward - 32 goroutines × 100 calls on one shared bucket: allowed ≤ burst+slop - Janitor: bucket idle 15 min → GC'd Docs: 14-configuration.md "Rate limiting" section updated; the "no-op in pure-Pebble" claim was wrong post-commit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The pure-Pebble path used a `noopLimiter` that allowed every request even when rate limits were configured. Silent foot-gun: operators saw the YAML knobs (`producer.requestsPerMinute`, `burstSize`, …) and trusted them; runtime ignored them.
This PR ships an in-process token-bucket limiter for the pure-Pebble path. Configuration now actually takes effect.
Design
What landed
Test plan
🤖 Generated with Claude Code