summaryrefslogtreecommitdiffstats
path: root/src/backoff.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-24 03:04:58 +0200
committertv <tv@krebsco.de>2026-10-24 03:05:17 +0200
commit251fe1e8e57d923bcf35dd284fbf30edd530506e (patch)
treef5e4a121d6261567b77fe9a4a4ad07aadbc7a66e /src/backoff.rs
parent9ef3dc3e7408caa658bb14b9cec1e0144d372a59 (diff)
consolidate backoff code
Diffstat (limited to 'src/backoff.rs')
-rw-r--r--src/backoff.rs58
1 files changed, 58 insertions, 0 deletions
diff --git a/src/backoff.rs b/src/backoff.rs
new file mode 100644
index 0000000..1f87b8d
--- /dev/null
+++ b/src/backoff.rs
@@ -0,0 +1,58 @@
+//! Exponential backoff: a delay that doubles, up to a limit, while something keeps
+//! failing, and starts over when it succeeds. Only the delay; each user keeps its own
+//! point in time (next attempt, deadline).
+
+use std::time::Duration;
+
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct Backoff {
+ initial: Duration,
+ max: Duration,
+ current: Duration,
+}
+
+impl Backoff {
+ pub(crate) const fn new(initial: Duration, max: Duration) -> Self {
+ Self {
+ initial,
+ max,
+ current: initial,
+ }
+ }
+
+ /// The delay to use now.
+ pub(crate) fn current(&self) -> Duration {
+ self.current
+ }
+
+ /// Doubles the delay, up to the limit.
+ pub(crate) fn grow(&mut self) {
+ self.current = self.current.saturating_mul(2).min(self.max);
+ }
+
+ /// The delay to use now; the next call gives twice as much (up to the limit).
+ pub(crate) fn next(&mut self) -> Duration {
+ let delay = self.current;
+ self.grow();
+ delay
+ }
+
+ /// Back to the initial delay.
+ pub(crate) fn reset(&mut self) {
+ self.current = self.initial;
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn doubles_up_to_the_limit_and_resets() {
+ let mut backoff = Backoff::new(Duration::from_secs(1), Duration::from_secs(5));
+ let delays: Vec<_> = (0..5).map(|_| backoff.next().as_secs()).collect();
+ assert_eq!(delays, [1, 2, 4, 5, 5]);
+ backoff.reset();
+ assert_eq!(backoff.current(), Duration::from_secs(1));
+ }
+}