Skip to main content

panopticon_core/hooks/core/
timeout.rs

1use crate::imports::*;
2use std::time::{Duration, Instant};
3
4/// A built-in interceptor hook that aborts the pipeline once a wall-clock
5/// deadline has passed.
6///
7/// The clock starts when the hook is attached, not when the pipeline
8/// runs — typically those are close enough that the distinction does
9/// not matter. The check fires before each step; an in-flight step is
10/// allowed to finish before the abort takes effect.
11pub struct Timeout {
12    name: String,
13    limit: Duration,
14}
15
16impl Timeout {
17    /// Constructs a timeout hook with the given wall-clock limit.
18    pub fn new(limit: Duration) -> Self {
19        Timeout {
20            name: "timeout".into(),
21            limit,
22        }
23    }
24
25    /// Overrides the hook name used in the abort message.
26    pub fn name(mut self, name: impl Into<String>) -> Self {
27        self.name = name.into();
28        self
29    }
30}
31
32impl From<Timeout> for Hook {
33    fn from(timeout: Timeout) -> Hook {
34        let limit = timeout.limit;
35        let start: Arc<Instant> = Arc::new(Instant::now());
36
37        Hook::interceptor(timeout.name, move |event, _store| {
38            if let HookEvent::BeforeStep { step_name, .. } = event {
39                let elapsed = start.elapsed();
40                if elapsed > limit {
41                    return HookAction::Abort(format!(
42                        "Pipeline exceeded timeout of {:.1}s (elapsed: {:.1}s) before step '{}'",
43                        limit.as_secs_f64(),
44                        elapsed.as_secs_f64(),
45                        step_name,
46                    ));
47                }
48            }
49            HookAction::Continue
50        })
51    }
52}