Fixed - RRateLimiter allows limit overcome. #3639

pull/3782/head
Nikita Koksharov 4 years ago
parent 787ddbe774
commit 4c98333dff

@ -211,8 +211,8 @@ public class RedissonRateLimiter extends RedissonExpirable implements RRateLimit
+ "end;"
+ "if tonumber(currentValue) < tonumber(ARGV[1]) then "
+ "local nearest = redis.call('zrangebyscore', permitsName, '(' .. (tonumber(ARGV[2]) - interval), '+inf', 'withscores', 'limit', 0, 1); "
+ "return tonumber(nearest[2]) - (tonumber(ARGV[2]) - interval);"
+ "local firstValue = redis.call('zrange', permitsName, 0, 0, 'withscores'); "
+ "return 3 + interval - (tonumber(ARGV[2]) - tonumber(firstValue[2]));"
+ "else "
+ "redis.call('zadd', permitsName, ARGV[2], struct.pack('fI', ARGV[3], ARGV[1])); "
+ "redis.call('decrby', valueName, ARGV[1]); "

@ -184,6 +184,56 @@ public class RedissonRateLimiterTest extends BaseTest {
assertThat(deleted).isTrue();
}
@Test
public void testConcurrency2() throws InterruptedException {
RRateLimiter rr = redisson.getRateLimiter("test");
rr.trySetRate(RateType.OVERALL, 18, 1, RateIntervalUnit.SECONDS);
Queue<Long> queue = new ConcurrentLinkedQueue<Long>();
AtomicLong counter = new AtomicLong();
ExecutorService pool = Executors.newFixedThreadPool(8);
for (int i = 0; i < 8; i++) {
pool.execute(new Runnable() {
@Override
public void run() {
try {
while (true) {
rr.acquire();
queue.add(System.currentTimeMillis());
if (counter.incrementAndGet() > 1000) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
assertThat(pool.awaitTermination(2, TimeUnit.MINUTES)).isTrue();
int count = 0;
long start = 0;
boolean skip = true;
for (Long value : queue) {
if (start == 0) {
start = value;
}
count++;
if (value - start >= 1000) {
if (!skip) {
assertThat(count).isLessThanOrEqualTo(18);
} else {
skip = false;
}
start = 0;
count = 0;
}
}
}
@Test
public void testConcurrency() throws InterruptedException {
RRateLimiter rr = redisson.getRateLimiter("test");

Loading…
Cancel
Save