governor/state/keyed/future.rs
1use crate::{
2 clock, errors::InsufficientCapacity, middleware::RateLimitingMiddleware,
3 state::keyed::KeyedStateStore, Jitter, NotUntil, RateLimiter,
4};
5use core::{hash::Hash, num::NonZeroU32};
6use futures_timer::Delay;
7
8#[cfg(feature = "std")]
9/// # Keyed rate limiters - `async`/`await`
10impl<K, S, C, MW> RateLimiter<K, S, C, MW>
11where
12 K: Hash + Eq + Clone,
13 S: KeyedStateStore<K>,
14 C: clock::ReasonablyRealtime,
15 MW: RateLimitingMiddleware<C::Instant, NegativeOutcome = NotUntil<C::Instant>>,
16{
17 /// Asynchronously resolves as soon as the rate limiter allows it.
18 ///
19 /// When polled, the returned future either resolves immediately (in the case where the rate
20 /// limiter allows it), or else triggers an asynchronous delay, after which the rate limiter
21 /// is polled again. This means that the future might resolve at some later time (depending
22 /// on what other measurements are made on the rate limiter).
23 ///
24 /// If multiple futures are dispatched against the rate limiter, it is advisable to use
25 /// [`until_ready_with_jitter`](#method.until_ready_with_jitter), to avoid thundering herds.
26 pub async fn until_key_ready(&self, key: &K) -> MW::PositiveOutcome {
27 self.until_key_ready_with_jitter(key, Jitter::NONE).await
28 }
29
30 /// Asynchronously resolves as soon as the rate limiter allows it, with a randomized wait
31 /// period.
32 ///
33 /// When polled, the returned future either resolves immediately (in the case where the rate
34 /// limiter allows it), or else triggers an asynchronous delay, after which the rate limiter
35 /// is polled again. This means that the future might resolve at some later time (depending
36 /// on what other measurements are made on the rate limiter).
37 ///
38 /// This method allows for a randomized additional delay between polls of the rate limiter,
39 /// which can help reduce the likelihood of thundering herd effects if multiple tasks try to
40 /// wait on the same rate limiter.
41 pub async fn until_key_ready_with_jitter(
42 &self,
43 key: &K,
44 jitter: Jitter,
45 ) -> MW::PositiveOutcome {
46 loop {
47 match self.check_key(key) {
48 Ok(x) => {
49 return x;
50 }
51 Err(negative) => {
52 let delay = Delay::new(jitter + negative.wait_time_from(self.clock.now()));
53 delay.await;
54 }
55 }
56 }
57 }
58
59 /// Asynchronously resolves as soon as the rate limiter allows it.
60 ///
61 /// This is similar to `until_key_ready` except it waits for an abitrary number
62 /// of `n` cells to be available.
63 ///
64 /// Returns `InsufficientCapacity` if the `n` provided exceeds the maximum
65 /// capacity of the rate limiter.
66 pub async fn until_key_n_ready(
67 &self,
68 key: &K,
69 n: NonZeroU32,
70 ) -> Result<MW::PositiveOutcome, InsufficientCapacity> {
71 self.until_key_n_ready_with_jitter(key, n, Jitter::NONE)
72 .await
73 }
74
75 /// Asynchronously resolves as soon as the rate limiter allows it, with a
76 /// randomized wait period.
77 ///
78 /// This is similar to `until_key_ready_with_jitter` except it waits for an
79 /// abitrary number of `n` cells to be available.
80 ///
81 /// Returns `InsufficientCapacity` if the `n` provided exceeds the maximum
82 /// capacity of the rate limiter.
83 pub async fn until_key_n_ready_with_jitter(
84 &self,
85 key: &K,
86 n: NonZeroU32,
87 jitter: Jitter,
88 ) -> Result<MW::PositiveOutcome, InsufficientCapacity> {
89 loop {
90 match self.check_key_n(key, n)? {
91 Ok(x) => {
92 return Ok(x);
93 }
94 Err(negative) => {
95 let delay = Delay::new(jitter + negative.wait_time_from(self.clock.now()));
96 delay.await;
97 }
98 }
99 }
100 }
101}