You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is actually still kind of buggy. You fix the TTL in Redis, but the retry-after headers will still be wrong.
This is the basic change that allows this to be fixed:
First, adjust the LUA Script so that it returns the current TTL as well as counter.
static private readonly LuaScript _atomicIncrement = LuaScript.Prepare("local count = redis.call(\"INCRBYFLOAT\", @key, tonumber(@delta)) local ttl = redis.call(\"TTL\", @key) if ttl == -1 then redis.call(\"EXPIRE\", @key, @timeout) end return { 'count', count, 'ttl', ttl }");
Then, adjust IncrementAsync as follows:
public async Task IncrementAsync(string counterId, TimeSpan interval, Func? RateIncrementer = null)
public async Task<RateLimitCounter> IncrementAsync(string counterId, TimeSpan interval, Func<double> RateIncrementer = null)
{
var cacheStart = DateTime.UtcNow;
var cached = await _connectionMultiplexer.GetDatabase().ScriptEvaluateAsync(_atomicIncrement, new { key = new RedisKey(counterId), timeout = interval.TotalSeconds, delta = RateIncrementer?.Invoke() ?? 1D });
var responseDict = cached.ToDictionary();
var ttlSeconds = (int)responseDict["ttl"];
if (ttlSeconds != -1)
cacheStart = cacheStart.Add(-interval).AddSeconds(ttlSeconds); // Subtract the amount of seconds the interval adds, then add the amount of seconds still left to live.
var count = (double)responseDict["count"];
return new RateLimitCounter
{
Count = count,
Timestamp = cacheStart
};
}
This makes it so since we don't have an actual 'first call'-time, we can just take the current time minus the interval plus the TTL, which gives us a first cache time which is within a second of the actual time, which should suffice for the accuracy of the rate limiting.
The timeout variable for the LUA Script is only used when no entry exists, so we can just always set that to interval.TotalSeconds.
Currently redis ttl is set to max value even if request is made at the end of interval. This can be confusing to API users and is misleading.
I suggest a small change to the Increment async method to calculate how much time there is left to next interval.
The text was updated successfully, but these errors were encountered: