canic_core/ops/ic/
timer.rs

1pub use crate::cdk::timers::TimerId;
2
3use crate::{
4    cdk::timers::{
5        clear_timer as cdk_clear_timer, set_timer as cdk_set_timer,
6        set_timer_interval as cdk_set_timer_interval,
7    },
8    model::metrics::{
9        system::{SystemMetricKind, SystemMetrics},
10        timer::{TimerMetrics, TimerMode},
11    },
12    ops::perf::PerfOps,
13    perf::perf_counter,
14};
15use std::{cell::RefCell, future::Future, rc::Rc, time::Duration};
16
17///
18/// TimerOps
19///
20
21pub struct TimerOps;
22
23impl TimerOps {
24    /// Schedules a one-shot timer.
25    /// The task is a single Future, consumed exactly once.
26    pub fn set(
27        delay: Duration,
28        label: impl Into<String>,
29        task: impl Future<Output = ()> + 'static,
30    ) -> TimerId {
31        let label = label.into();
32
33        SystemMetrics::increment(SystemMetricKind::TimerScheduled);
34        TimerMetrics::ensure(TimerMode::Once, delay, &label);
35
36        cdk_set_timer(delay, async move {
37            TimerMetrics::increment(TimerMode::Once, delay, &label);
38
39            let start = perf_counter();
40            task.await;
41            let end = perf_counter();
42
43            PerfOps::record(&label, end.saturating_sub(start));
44        })
45    }
46
47    /// Schedules a repeating timer.
48    /// The task is a closure that produces a fresh Future on each tick.
49    pub fn set_interval<F, Fut>(interval: Duration, label: impl Into<String>, task: F) -> TimerId
50    where
51        F: FnMut() -> Fut + 'static,
52        Fut: Future<Output = ()> + 'static,
53    {
54        let label = label.into();
55
56        SystemMetrics::increment(SystemMetricKind::TimerScheduled);
57        TimerMetrics::ensure(TimerMode::Interval, interval, &label);
58
59        let task = Rc::new(RefCell::new(task));
60
61        cdk_set_timer_interval(interval, move || {
62            let label = label.clone();
63            let interval = interval;
64            let task = Rc::clone(&task);
65
66            async move {
67                TimerMetrics::increment(TimerMode::Interval, interval, &label);
68
69                let start = perf_counter();
70                let fut = { (task.borrow_mut())() };
71                fut.await;
72                let end = perf_counter();
73
74                PerfOps::record(&label, end.saturating_sub(start));
75            }
76        })
77    }
78
79    /// Clears a previously scheduled timer.
80    pub fn clear(id: TimerId) {
81        cdk_clear_timer(id);
82    }
83}