Skip to content

Commit e468fac

Browse files
committed
fix(scanner-daemon): replace the float jitter arithmetic with integer arithmetic
The production-code pass of the static checks denies clippy::float_arithmetic (-D clippy::float_arithmetic in do_checks.sh), which the jitter computation in the backoff schedule violated; the local verification had only replicated the first clippy pass (all-targets), where that lint is not enabled. The jitter is now computed in integer arithmetic: a uniformly random percentage in [80, 120] is applied via Duration's u32 multiplication and division, with the test bounds derived the same way.
1 parent 2c3470c commit e468fac

1 file changed

Lines changed: 16 additions & 9 deletions

File tree

‎api-server/scanner-daemon/src/backoff.rs‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ use std::time::Duration;
2323
use randomness::{Rng, RngExt as _};
2424

2525
/// The relative jitter applied to every delay: the actual delay is in
26-
/// `[delay * (1 - JITTER), delay * (1 + JITTER)]`.
27-
const JITTER: f64 = 0.2;
26+
/// `[delay * (100 - JITTER_PERCENT) / 100, delay * (100 + JITTER_PERCENT) / 100]`.
27+
const JITTER_PERCENT: i64 = 20;
2828

29-
/// The exponential backoff schedule between connection attempts.
29+
/// The exponential backoff schedule between connection attempts: the delay starts at the
30+
/// initial delay, doubles on every attempt up to the maximum, and is jittered; a successful
31+
/// connection resets the schedule (see [`ReconnectBackoff::reset`]).
3032
#[derive(Debug)]
3133
pub struct ReconnectBackoff {
3234
initial_delay: Duration,
@@ -68,19 +70,24 @@ impl ReconnectBackoff {
6870
}
6971

7072
/// Returns the delay to wait before the next connection attempt and advances the schedule
71-
/// (doubling it, up to the maximum). The returned delay is jittered by ±[`JITTER`], so the
72-
/// returned value can exceed `max_delay` by up to 20%.
73+
/// (doubling it, up to the maximum). The returned delay is jittered by
74+
/// ±[`JITTER_PERCENT`]%, so the returned value can exceed `max_delay` by up to 20%.
7375
pub fn next_delay(&mut self, rng: &mut impl Rng) -> Duration {
7476
let base_delay = self.next_delay;
7577
self.next_delay = std::cmp::min(base_delay * 2, self.max_delay);
7678
apply_jitter(base_delay, rng)
7779
}
7880
}
7981

80-
/// Jitter the given delay by a uniformly random factor in `[1 - JITTER, 1 + JITTER]`.
82+
/// Jitter the given delay by a uniformly random percentage in
83+
/// `[100 - JITTER_PERCENT, 100 + JITTER_PERCENT]`.
84+
///
85+
/// Note: integer arithmetic only (the production-code clippy configuration rejects floating
86+
/// point arithmetic); the intermediate products cannot overflow, because the percentages are
87+
/// small and `Duration` multiplication takes a `u32`.
8188
fn apply_jitter(delay: Duration, rng: &mut impl Rng) -> Duration {
82-
let jitter_fraction = rng.random_range(-JITTER..=JITTER);
83-
delay.mul_f64(1.0 + jitter_fraction)
89+
let percent = (100 + rng.random_range(-JITTER_PERCENT..=JITTER_PERCENT)) as u32;
90+
delay * percent / 100
8491
}
8592

8693
#[cfg(test)]
@@ -92,7 +99,7 @@ mod tests {
9299
const MAX_DELAY: Duration = Duration::from_secs(60);
93100

94101
fn jitter_bounds(delay: Duration) -> (Duration, Duration) {
95-
(delay.mul_f64(1.0 - JITTER), delay.mul_f64(1.0 + JITTER))
102+
(delay * 80 / 100, delay * 120 / 100)
96103
}
97104

98105
#[track_caller]

0 commit comments

Comments
 (0)