gioser

tawasuyu/brahman

Rust 334TOML 129Markdown 39JSON 174745 Definiciones

⎇ 545dd59c727b2c6b9752ab4b29de64ad0d24b35c crates/runtime/sandokan-lifecycle/src/backoff.rs Rust · 68 líneas · 2.0 KB Historia Quién tocó qué crudo

feat(sandokan-lifecycle): A4 — primitivas de lifecycle agnósticas 545dd59c7 · sergio ·

1//! Backoff exponencial con tope.
2
3use std::time::Duration;
4
5/// Calculador de backoff exponencial. Cada `next_delay()` devuelve el
6/// delay actual y luego lo duplica, hasta saturar en `max`.
7#[derive(Debug, Clone)]
8pub struct Backoff {
9    base: Duration,
10    max: Duration,
11    current: Duration,
12}
13
14impl Backoff {
15    /// Crea un backoff que arranca en `base` y satura en `max`.
16    /// Si `base > max`, `base` se clampa a `max`.
17    pub fn new(base: Duration, max: Duration) -> Self {
18        let base = base.min(max);
19        Self { base, max, current: base }
20    }
21
22    /// Devuelve el delay actual y escala el siguiente (×2, capeado a `max`).
23    pub fn next_delay(&mut self) -> Duration {
24        let delay = self.current;
25        self.current = (self.current * 2).min(self.max);
26        delay
27    }
28
29    /// Vuelve al delay base (tras un éxito).
30    pub fn reset(&mut self) {
31        self.current = self.base;
32    }
33
34    /// Delay que devolvería el próximo `next_delay()` sin consumirlo.
35    pub fn peek(&self) -> Duration {
36        self.current
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn escalates_then_caps() {
46        let mut b = Backoff::new(Duration::from_millis(100), Duration::from_millis(800));
47        assert_eq!(b.next_delay(), Duration::from_millis(100));
48        assert_eq!(b.next_delay(), Duration::from_millis(200));
49        assert_eq!(b.next_delay(), Duration::from_millis(400));
50        assert_eq!(b.next_delay(), Duration::from_millis(800));
51        assert_eq!(b.next_delay(), Duration::from_millis(800)); // capeado
52    }
53
54    #[test]
55    fn reset_returns_to_base() {
56        let mut b = Backoff::new(Duration::from_millis(100), Duration::from_secs(30));
57        b.next_delay();
58        b.next_delay();
59        b.reset();
60        assert_eq!(b.next_delay(), Duration::from_millis(100));
61    }
62
63    #[test]
64    fn base_clamped_to_max() {
65        let mut b = Backoff::new(Duration::from_secs(10), Duration::from_secs(1));
66        assert_eq!(b.next_delay(), Duration::from_secs(1));
67    }
68}