diff --git a/spring-cloud-gateway-server-webflux/src/main/resources/META-INF/scripts/request_rate_limiter.lua b/spring-cloud-gateway-server-webflux/src/main/resources/META-INF/scripts/request_rate_limiter.lua index 37033036b3..aafdcb671d 100644 --- a/spring-cloud-gateway-server-webflux/src/main/resources/META-INF/scripts/request_rate_limiter.lua +++ b/spring-cloud-gateway-server-webflux/src/main/resources/META-INF/scripts/request_rate_limiter.lua @@ -5,7 +5,13 @@ local timestamp_key = KEYS[2] local rate = tonumber(ARGV[1]) local capacity = tonumber(ARGV[2]) -local now = tonumber(ARGV[3]) or redis.call('TIME')[1] + +local now = tonumber(ARGV[3]) +if not now then + local redis_time = redis.call('TIME') + now = redis_time[1] + (redis_time[2] / 1000000) +end + local requested = tonumber(ARGV[4]) local fill_time = capacity / rate diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterLuaScriptTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterLuaScriptTests.java index dd04862f61..fcf17a45d3 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterLuaScriptTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterLuaScriptTests.java @@ -75,6 +75,10 @@ static List getArgs(long rate, long capacity, long now, long requested) return Arrays.asList(rate + "", capacity + "", now + "", requested + ""); } + static List getArgsWithRedisTime(long rate, long capacity, long requested) { + return Arrays.asList(rate + "", capacity + "", "", requested + ""); + } + @Test public void testNewAccess() { long rate = 1; @@ -164,6 +168,24 @@ public void testCapacityExceedsMaxInt() { assertThat(result.get(1)).isEqualTo(REDIS_LUA_MAX_SAFE_INTEGER - 1); } + @Test + public void testRedisTimeSupportsSubSecondRefill() throws InterruptedException { + long rate = 10; + long capacity = 10; + List keys = getKeys("sub_second_refill"); + + List args = getArgsWithRedisTime(rate, capacity, capacity); + List first = redisTemplate.execute(redisScript, keys, args).blockFirst(); + assertThat(first.get(0)).isEqualTo(1); + assertThat(first.get(1)).isEqualTo(0); + + Thread.sleep(250); + + args = getArgsWithRedisTime(rate, capacity, 1); + List second = redisTemplate.execute(redisScript, keys, args).blockFirst(); + assertThat(second.get(0)).isEqualTo(1); + } + @EnableAutoConfiguration @SpringBootConfiguration public static class TestConfig {