From d120a32904954a2f23a290e5136b64eb850e6c60 Mon Sep 17 00:00:00 2001 From: spiral Date: Sat, 18 Mar 2023 20:44:50 -0400 Subject: [PATCH] fix ratelimits --- services/api/src/middleware/ratelimit.lua | 17 +++++++++++------ services/api/src/middleware/ratelimit.rs | 11 +++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/services/api/src/middleware/ratelimit.lua b/services/api/src/middleware/ratelimit.lua index b7e58ec9..96b38235 100644 --- a/services/api/src/middleware/ratelimit.lua +++ b/services/api/src/middleware/ratelimit.lua @@ -1,12 +1,13 @@ --- Copyright (c) 2017 Pavel Pravosud --- https://github.com/rwz/redis-gcra/blob/master/vendor/perform_gcra_ratelimit.lua +-- this script has side-effects, so it requires replicate commands mode +-- redis.replicate_commands() local rate_limit_key = KEYS[1] local burst = ARGV[1] local rate = ARGV[2] local period = ARGV[3] --- local cost = tonumber(ARGV[4]) -local cost = 1 + +-- we're only ever asking for 1 request at a time +local cost = 1 --local cost = tonumber(ARGV[4]) local emission_interval = period / rate local increment = emission_interval * cost @@ -44,7 +45,7 @@ if remaining < 0 then local retry_after = diff * -1 return { 0, -- remaining - retry_after, + tostring(retry_after), reset_after, } end @@ -54,4 +55,8 @@ if reset_after > 0 then redis.call("SET", rate_limit_key, new_tat, "EX", math.ceil(reset_after)) end local retry_after = -1 -return {remaining, retry_after, reset_after} \ No newline at end of file +return { + remaining, + tostring(retry_after), + reset_after +} diff --git a/services/api/src/middleware/ratelimit.rs b/services/api/src/middleware/ratelimit.rs index 36c3e618..d95ee04d 100644 --- a/services/api/src/middleware/ratelimit.rs +++ b/services/api/src/middleware/ratelimit.rs @@ -88,7 +88,7 @@ pub async fn do_request_ratelimited( // local burst = ARGV[1] // local rate = ARGV[2] // local period = ARGV[3] - // return {remaining, retry_after, reset_after} + // return {remaining, tostring(retry_after), reset_after} let resp = redis .evalsha::<(i32, String, u64), String, Vec<&str>, Vec>( scriptsha, @@ -99,14 +99,21 @@ pub async fn do_request_ratelimited( match resp { Ok((mut remaining, retry_after, reset_after)) => { + // redis's lua doesn't support returning floats + let retry_after: f64 = retry_after + .parse() + .expect("got something that isn't a f64 from redis"); + let mut response = if remaining > 0 { next.run(request).await } else { + println!("{}", reset_after); json_err( StatusCode::TOO_MANY_REQUESTS, format!( // todo: the retry_after is horribly wrong - r#"{{"message":"429: too many requests","retry_after":{retry_after}}}"# + r#"{{"message":"429: too many requests","retry_after":{},"code":0}}"#, + (retry_after * 1_000_f64).ceil() as u64 ), ) };