Fix: RedisTokenBucketRateLimiter does not refill and block randomly anymore #47
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.
Fixes #46
This PR reworks the Lua script used by the
RedisTokenBucketManager
in a few ways. The primary goal is to fix the issues mentioned in #46. Summary of the changes:now
is generated by Redis now, which is safe due to the use ofredis.replicate_commands()
. By letting Redis take the time itself, all requests are clocked by the same system, guaranteeing best accuracy.TimeSpan
s.redis.call('GET', ...)
calls have been replaced withredis.call('MGET', ...)
to safe a round-trip to the database.current_tokens
together with the timestamp are only persisted, if the request is allowed.periods_until_full
multiplied by theperiod
(duration). This fixes the first issue described in The RedisTokenBucketRateLimiter refills the bucket immediately after some timeout #46.now
anymore but thetime_of_last_replenishment
. This fixes the second issue described in The RedisTokenBucketRateLimiter refills the bucket immediately after some timeout #46.Besides the changes to the Lua script, the PR also includes the following other changes:
IRedisDatabase.ScriptEvaluate()
are now explicitly flagged as(RedisKey)
or(RedisValue)
respectively. This ensures that the parameters are mapped to theKEYS[]
andARGS[]
arrays correctly, which is important for correct script execution (especially in clusters).retry_after
(in milliseconds), which is0
if the request wasallowed
or the milliseconds until the next token is generated ifnot allowed
. This value is returned by the rate limiter in rounded up seconds.