Skip to main content

boson_backend_sql_common/
enqueue_rate.rs

1//! Process-local sliding-window limiter for enqueues per task per second.
2
3use std::collections::{HashMap, VecDeque};
4use std::sync::Mutex;
5use std::time::Instant;
6
7/// Tracks recent enqueue timestamps per task name (1-second sliding window).
8#[derive(Debug, Default)]
9pub struct EnqueueRateLimiter {
10    inner: Mutex<HashMap<String, VecDeque<Instant>>>,
11}
12
13impl EnqueueRateLimiter {
14    /// New empty limiter.
15    #[must_use]
16    pub fn new() -> Self {
17        Self::default()
18    }
19
20    /// Returns `true` if this enqueue is allowed under `max_per_second` for `task_name`.
21    ///
22    /// Records the enqueue timestamp when allowed. `max_per_second == 0` means unlimited.
23    pub fn try_record(&self, task_name: &str, max_per_second: u32) -> bool {
24        if max_per_second == 0 {
25            return true;
26        }
27        let mut guard = self.inner.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
28        let now = Instant::now();
29        let allowed = {
30            let window = guard.entry(task_name.to_string()).or_default();
31            while let Some(front) = window.front().copied() {
32                if now.duration_since(front).as_secs() >= 1 {
33                    window.pop_front();
34                } else {
35                    break;
36                }
37            }
38            if window.len() >= max_per_second as usize {
39                false
40            } else {
41                window.push_back(now);
42                true
43            }
44        };
45        drop(guard);
46        allowed
47    }
48}