Skip to content

Commit 9286012

Browse files
committed
Improve parametrized Rng
- Adds more tests
1 parent eb7ba08 commit 9286012

1 file changed

Lines changed: 69 additions & 33 deletions

File tree

  • crates/charon/src/expbackoff

crates/charon/src/expbackoff/mod.rs

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
use std::{marker::PhantomData, time};
2-
use tower::{retry::backoff::Backoff, util::rng::Rng};
1+
use std::time;
2+
use tower::{
3+
retry::backoff::Backoff,
4+
util::rng::{HasherRng, Rng},
5+
};
36

47
/// A jittered [exponential backoff] strategy.
58
///
@@ -63,9 +66,9 @@ where
6366
type Future = tokio::time::Sleep;
6467

6568
fn next_backoff(&mut self) -> Self::Future {
66-
self.retries += 1;
67-
6869
let duration = self.backoff();
70+
self.tried();
71+
6972
tokio::time::sleep(duration)
7073
}
7174
}
@@ -76,7 +79,7 @@ pub struct ExponentialBackoffBuilder<R> {
7679
multiplier: f64,
7780
jitter: f64,
7881
max_delay: time::Duration,
79-
_rng: PhantomData<R>,
82+
rng: R,
8083
}
8184

8285
type Result<T> = std::result::Result<T, InvalidBackoff>;
@@ -86,34 +89,31 @@ type Result<T> = std::result::Result<T, InvalidBackoff>;
8689
#[error("Invalid backoff configuration: {0}")]
8790
pub struct InvalidBackoff(&'static str);
8891

89-
impl<R> ExponentialBackoffBuilder<R>
90-
where
91-
R: Rng + Default,
92-
{
92+
impl<R> ExponentialBackoffBuilder<R> {
9393
/// Backoff configuration with the default values specified at https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
9494
///
9595
/// This should be useful for callers who want to configure backoff with
9696
/// non-default values only for a subset of the options.
9797
///
9898
/// Copied from [google.golang.org/grpc@v1.48.0/backoff/backoff.go]
99-
pub fn default() -> Self {
100-
Self {
99+
pub fn default() -> ExponentialBackoffBuilder<HasherRng> {
100+
ExponentialBackoffBuilder {
101101
base_delay: time::Duration::from_secs(1),
102102
multiplier: 1.6,
103103
jitter: 0.2,
104104
max_delay: time::Duration::from_secs(120),
105-
_rng: PhantomData,
105+
rng: HasherRng::default(),
106106
}
107107
}
108108

109109
/// Common configuration for fast backoff.
110-
pub fn fast_config() -> Self {
111-
Self {
110+
pub fn fast_config() -> ExponentialBackoffBuilder<HasherRng> {
111+
ExponentialBackoffBuilder {
112112
base_delay: time::Duration::from_millis(100),
113113
multiplier: 1.6,
114114
jitter: 0.2,
115115
max_delay: time::Duration::from_secs(5),
116-
_rng: PhantomData,
116+
rng: HasherRng::default(),
117117
}
118118
}
119119

@@ -142,6 +142,17 @@ where
142142
self
143143
}
144144

145+
/// Set the random number generator to use for jittering.
146+
pub fn with_rng<T>(self, rng: T) -> ExponentialBackoffBuilder<T> {
147+
ExponentialBackoffBuilder {
148+
base_delay: self.base_delay,
149+
multiplier: self.multiplier,
150+
jitter: self.jitter,
151+
max_delay: self.max_delay,
152+
rng,
153+
}
154+
}
155+
145156
/// Construct a new [`ExponentialBackoff`] instance from the builder.
146157
pub fn build(self) -> Result<ExponentialBackoff<R>> {
147158
if self.base_delay > self.max_delay {
@@ -168,7 +179,7 @@ where
168179
jitter: self.jitter,
169180
multiplier: self.multiplier,
170181
max_delay: self.max_delay,
171-
rng: R::default(),
182+
rng: self.rng,
172183
retries: 0,
173184
})
174185
}
@@ -180,26 +191,20 @@ mod tests {
180191
use core::time::Duration;
181192
use tower::util::rng::Rng;
182193

183-
#[test]
184-
fn default_config() {
185-
struct ConstRng;
186-
187-
impl Rng for ConstRng {
188-
fn next_f64(&mut self) -> f64 {
189-
0.5
190-
}
194+
struct Const(f64);
191195

192-
fn next_u64(&mut self) -> u64 {
193-
panic!("not implemented")
194-
}
196+
impl Rng for Const {
197+
fn next_f64(&mut self) -> f64 {
198+
self.0
195199
}
196200

197-
impl Default for ConstRng {
198-
fn default() -> Self {
199-
ConstRng
200-
}
201+
fn next_u64(&mut self) -> u64 {
202+
0
201203
}
204+
}
202205

206+
#[test]
207+
fn default_config() {
203208
let backoffs: Vec<Duration> = vec![
204209
Duration::from_secs(1),
205210
Duration::from_secs(1) + Duration::from_millis(600),
@@ -216,8 +221,39 @@ mod tests {
216221
Duration::from_mins(2),
217222
];
218223

219-
let mut backoff: ExponentialBackoff<ConstRng> = ExponentialBackoffBuilder::default()
220-
.with_jitter(0.5)
224+
let mut backoff = ExponentialBackoffBuilder::<Const>::default()
225+
.with_rng(Const(0.5))
226+
.build()
227+
.unwrap();
228+
229+
for expected in backoffs {
230+
let duration = backoff.backoff();
231+
backoff.tried();
232+
233+
assert!(duration - expected <= Duration::from_millis(10));
234+
}
235+
}
236+
237+
#[test]
238+
fn default_config_max_jitter() {
239+
let backoffs: Vec<Duration> = vec![
240+
Duration::from_secs(1),
241+
Duration::from_secs(1) + Duration::from_millis(920),
242+
Duration::from_secs(3) + Duration::from_millis(70),
243+
Duration::from_secs(4) + Duration::from_millis(910),
244+
Duration::from_secs(7) + Duration::from_millis(860),
245+
Duration::from_secs(12) + Duration::from_millis(580),
246+
Duration::from_secs(20) + Duration::from_millis(130),
247+
Duration::from_secs(32) + Duration::from_millis(210),
248+
Duration::from_secs(51) + Duration::from_millis(530),
249+
Duration::from_mins(1) + Duration::from_secs(22) + Duration::from_millis(460),
250+
Duration::from_mins(2) + Duration::from_secs(11) + Duration::from_millis(940),
251+
Duration::from_mins(2) + Duration::from_secs(24),
252+
Duration::from_mins(2) + Duration::from_secs(24),
253+
];
254+
255+
let mut backoff: ExponentialBackoff<Const> = ExponentialBackoffBuilder::<Const>::default()
256+
.with_rng(Const(1.0))
221257
.build()
222258
.unwrap();
223259

0 commit comments

Comments
 (0)