Skip to content

Commit 14eb42f

Browse files
committed
Run rate limiter garbage collection before inserting new user
Move the GC pass from after insertion to before, so that stale entries are reclaimed before allocating a new bucket. This avoids unnecessary growth of the user map between GC cycles. AI tools were used in preparing this commit.
1 parent 140451e commit 14eb42f

File tree

1 file changed

+14
-8
lines changed

1 file changed

+14
-8
lines changed

src/payment/asynchronous/rate_limiter.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pub(crate) struct RateLimiter {
2323
max_idle: Duration,
2424
}
2525

26+
const MAX_USERS: usize = 10_000;
27+
2628
struct Bucket {
2729
tokens: u32,
2830
last_refill: Instant,
@@ -36,10 +38,19 @@ impl RateLimiter {
3638
pub(crate) fn allow(&mut self, user_id: &[u8]) -> bool {
3739
let now = Instant::now();
3840

39-
let entry = self.users.entry(user_id.to_vec());
40-
let is_new_user = matches!(entry, std::collections::hash_map::Entry::Vacant(_));
41+
let is_new_user = !self.users.contains_key(user_id);
42+
43+
if is_new_user {
44+
self.garbage_collect(self.max_idle);
45+
if self.users.len() >= MAX_USERS {
46+
return false;
47+
}
48+
}
4149

42-
let bucket = entry.or_insert(Bucket { tokens: self.capacity, last_refill: now });
50+
let bucket = self
51+
.users
52+
.entry(user_id.to_vec())
53+
.or_insert(Bucket { tokens: self.capacity, last_refill: now });
4354

4455
let elapsed = now.duration_since(bucket.last_refill);
4556
let tokens_to_add = (elapsed.as_secs_f64() / self.refill_interval.as_secs_f64()) as u32;
@@ -56,11 +67,6 @@ impl RateLimiter {
5667
false
5768
};
5869

59-
// Each time a new user is added, we take the opportunity to clean up old rate limits.
60-
if is_new_user {
61-
self.garbage_collect(self.max_idle);
62-
}
63-
6470
allow
6571
}
6672

0 commit comments

Comments
 (0)