You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hugegraph.apache.org by ji...@apache.org on 2026/10/08 15:35:03 UTC
(hugegraph) 13/15: fix(server): defer the first rate limit reset
This is an automated email from the ASF dual-hosted git repository.
imbajin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hugegraph.git
commit ea4994a96747f17d767bf3ab97740880194d7b5a
Author: imbajin <ji...@apache.org>
AuthorDate: Thu Oct 8 20:31:40 2026 +0800
fix(server): defer the first rate limit reset
- start the first reset after the configured interval
- preserve the initial request window
- cover fixed-window timing boundaries
---
.../util/FixedTimerWindowRateLimiter.java | 8 +++-
.../hugegraph/unit/util/RateLimiterTest.java | 52 ++++++++++++++++++++++
2 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/util/FixedTimerWindowRateLimiter.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/util/FixedTimerWindowRateLimiter.java
index 0163656d5..7b08204bb 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/util/FixedTimerWindowRateLimiter.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/util/FixedTimerWindowRateLimiter.java
@@ -34,7 +34,11 @@ public class FixedTimerWindowRateLimiter implements RateLimiter {
private final int limit;
public FixedTimerWindowRateLimiter(int limitPerSecond) {
- this.timer = new Timer("RateAuditLog", true);
+ this(limitPerSecond, new Timer("RateAuditLog", true));
+ }
+
+ FixedTimerWindowRateLimiter(int limitPerSecond, Timer timer) {
+ this.timer = timer;
this.count = new LongAdder();
this.limit = limitPerSecond;
// Count will be reset if hit limit (run once per 1000ms)
@@ -45,7 +49,7 @@ public class FixedTimerWindowRateLimiter implements RateLimiter {
count.reset();
}
}
- }, 0L, RESET_PERIOD);
+ }, RESET_PERIOD, RESET_PERIOD);
}
@Override
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/util/RateLimiterTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/util/RateLimiterTest.java
index 111b63942..4ace25217 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/util/RateLimiterTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/util/RateLimiterTest.java
@@ -17,6 +17,9 @@
package org.apache.hugegraph.unit.util;
+import java.lang.reflect.Constructor;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.concurrent.atomic.LongAdder;
import org.apache.hugegraph.testutil.Assert;
@@ -74,6 +77,55 @@ public abstract class RateLimiterTest {
return new FixedTimerWindowRateLimiter(rate);
}
+ @Test
+ public void testInitialTimerWindow() throws Exception {
+ try (RecordingTimer timer = new RecordingTimer()) {
+ Constructor<FixedTimerWindowRateLimiter> constructor =
+ FixedTimerWindowRateLimiter.class.getDeclaredConstructor(int.class, Timer.class);
+ constructor.setAccessible(true);
+ RateLimiter limiter = constructor.newInstance(400, timer);
+
+ // The initial reset must wait for a complete window, even if the timer thread starts late.
+ Assert.assertEquals(RateLimiter.RESET_PERIOD, timer.delay);
+ Assert.assertEquals(RateLimiter.RESET_PERIOD, timer.period);
+ for (int i = 0; i < 400; i++) {
+ Assert.assertTrue(limiter.tryAcquire());
+ }
+ LongAdder count = Whitebox.getInternalState(limiter, "count");
+ Assert.assertEquals(400, count.intValue());
+ Assert.assertFalse(limiter.tryAcquire());
+
+ timer.task.run();
+ Assert.assertEquals(0, count.intValue());
+ Assert.assertTrue(limiter.tryAcquire());
+ timer.task.run();
+ Assert.assertEquals(1, count.intValue());
+ }
+ }
+
+ private static class RecordingTimer extends Timer implements AutoCloseable {
+
+ private TimerTask task;
+ private long delay;
+ private long period;
+
+ private RecordingTimer() {
+ super("RateLimiterTest", true);
+ }
+
+ @Override
+ public void schedule(TimerTask task, long delay, long period) {
+ this.task = task;
+ this.delay = delay;
+ this.period = period;
+ }
+
+ @Override
+ public void close() {
+ this.cancel();
+ }
+ }
+
@Test
public void testTryAcquireAfterPeriod() throws Exception {
int rateLimit = 400;