execution_policy/
event.rs1use std::sync::Arc;
6use std::time::Duration;
7
8use crate::error::BreakerState;
9
10#[non_exhaustive]
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum Event {
14 AttemptFailed { attempt: u32 },
16 AttemptTimedOut { attempt: u32 },
18 RetryScheduled { attempt: u32, delay: Duration },
20 Succeeded { attempts: u32 },
22 GaveUp { attempts: u32 },
24 CircuitStateChanged { to: BreakerState },
26 ConcurrencyRejected,
28 RetryBudgetExhausted { attempts: u32 },
30}
31
32pub(crate) type EventHook = Arc<dyn Fn(&Event) + Send + Sync>;
35
36#[inline]
39pub(crate) fn emit(hook: &Option<EventHook>, make: impl FnOnce() -> Event) {
40 if let Some(h) = hook {
41 h(&make());
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use std::sync::Mutex;
49
50 #[test]
51 fn emit_skips_when_no_hook() {
52 let none: Option<EventHook> = None;
53 let called = std::cell::Cell::new(false);
55 emit(&none, || {
56 called.set(true);
57 Event::Succeeded { attempts: 1 }
58 });
59 assert!(
60 !called.get(),
61 "event must not be constructed without a hook"
62 );
63 }
64
65 #[test]
66 fn emit_invokes_hook() {
67 let seen: Arc<Mutex<Vec<Event>>> = Arc::new(Mutex::new(Vec::new()));
68 let sink = Arc::clone(&seen);
69 let hook: Option<EventHook> = Some(Arc::new(move |e: &Event| {
70 sink.lock().unwrap().push(e.clone())
71 }));
72 emit(&hook, || Event::Succeeded { attempts: 3 });
73 assert_eq!(
74 seen.lock().unwrap().as_slice(),
75 &[Event::Succeeded { attempts: 3 }]
76 );
77 }
78}