Repository navigation
fix(limit-count): keep delayed sync counters per rule - #14064
Open
lordcheng10 wants to merge 3 commits into
Open
lordcheng10 wants to merge 3 commits into
lordcheng10 wants to merge 3 commits into
Conversation
With multiple rules and sync_interval, the delayed syncer id was derived only from the plugin instance, so all rules shared one queue and one timer. The timer flushes every queued key through the limiter of the syncer that started it, so keys belonging to other rules were synced using the wrong count and time_window, and their Remaining header was overwritten with the first rule's value after each sync. Give each rule its own syncer id, so every rule has its own queue, timer and limiter. Add a regression test with two rules (count 5/100) that checks the remaining headers before and after a delayed sync.
Contributor
Author
Contributor
Author
|
CI note: the current failures are all in the dependency-install step, before any test runs: They reproduce on the same workflow for other branches as well; |
2 of 5 tasks
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.
Description
Fix the
limit-countplugin corrupting per-rule counters when theredis/redis-cluster/redis-sentinelpolicy is used together withsync_intervaland multiplerules.With
rules, every rule creates its own limiter (rule.count,rule.time_window), but the delayed-sync instance id was derived only from theplugin name, policy and
_vid:so all rules of one plugin instance shared a single delayed-sync queue and a
single sync timer.
sync_key()flushes every queued key throughself.limiter, which belongs to whichever rule started the timer. Keys of theother rules were therefore synced to Redis using the wrong
countandtime_window, andsync_to_shm()stored that wrong remaining value for theirkeys.
The observable effect matches #14063: right after the first request each
X-<prefix>-RateLimit-Remainingheader is correct, but once the delayed syncruns, the remaining value of every other rule becomes the value that the first
rule's limiter produces (for example rule 2 with
count: 500jumps to theremaining of rule 1 with
count: 30).Fix: give each rule its own syncer id by appending the rule index, so each rule
gets its own queue, timer and limiter.
get_rules()now records the stablerule index (
idx), which is1for the single-rule configuration, so theexisting behaviour for configurations without
rulesis unchanged.This only changes the delayed-sync bookkeeping; the rate-limiting decision
path, Redis key format and headers are untouched.
Which issue(s) this PR fixes:
Fixes #14063
Checklist
Additional notes
No documentation change is needed: the configuration surface and the
documented
sync_intervalsemantics are unchanged, this only fixes theinternal bookkeeping that broke per-rule counters.
Regression test added to
t/plugin/limit-count-redis-delayed-sync2.t:count: 5,time_window: 10andcount: 100,time_window: 20) withsync_interval: 0.5;4/99on the first request and3/98after the delayedsync. Without the fix the second rule is synced through the first rule's
limiter and reports
3instead of98.Reviewer note on verification: this environment has no OpenResty or Redis, so
prove t/plugin/limit-count-redis-delayed-sync2.tcould not be executedlocally. The failure path was verified by tracing the code: the timer closure
captures the syncer of the rule that started it,
sync_key()usesself.limiterfor every key in the shared queue, and with per-rule syncer idseach queue only ever contains keys of its own rule. CI is expected to run the
full test file.
Upgrade note: the syncer id changes once, so delayed-sync queues created by the
previous version are not drained after an in-place upgrade. They expire with
the shared dict and contain only pending counter deltas, not configuration.