canic_core/ops/
timer.rs

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