qubit_executor/schedule/scheduled_executor_service.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use std::time::{
11 Duration,
12 Instant,
13};
14
15use qubit_function::{
16 Callable,
17 Runnable,
18};
19
20use crate::service::{
21 ExecutorService,
22 SubmissionError,
23};
24
25/// Managed executor service with delayed and instant-based submission support.
26///
27/// `ScheduledExecutorService` extends [`ExecutorService`] with per-task timing.
28/// A normal `submit` call is an immediate submission; `schedule` and
29/// `schedule_at` accept work now but delay the task start until the requested
30/// time. Successful submission only means the service accepted the scheduled
31/// task. Task success, failure, panic, or cancellation is observed through the
32/// returned tracked handle.
33pub trait ScheduledExecutorService: ExecutorService {
34 /// Schedules a runnable task to start after the supplied delay.
35 ///
36 /// # Parameters
37 ///
38 /// * `delay` - Minimum delay before the task becomes runnable.
39 /// * `task` - Runnable to execute after the delay elapses.
40 ///
41 /// # Returns
42 ///
43 /// A tracked handle for observing or cancelling the scheduled task.
44 ///
45 /// # Errors
46 ///
47 /// Returns [`SubmissionError`] when the service refuses the task before
48 /// accepting it.
49 #[inline]
50 fn schedule<T, E>(&self, delay: Duration, task: T) -> Result<Self::TrackedHandle<(), E>, SubmissionError>
51 where
52 T: Runnable<E> + Send + 'static,
53 E: Send + 'static,
54 {
55 let mut task = task;
56 self.schedule_callable(delay, move || task.run())
57 }
58
59 /// Schedules a callable task to start after the supplied delay.
60 ///
61 /// # Parameters
62 ///
63 /// * `delay` - Minimum delay before the task becomes runnable.
64 /// * `task` - Callable to execute after the delay elapses.
65 ///
66 /// # Returns
67 ///
68 /// A tracked handle for observing or cancelling the scheduled task.
69 ///
70 /// # Errors
71 ///
72 /// Returns [`SubmissionError`] when the service refuses the task before
73 /// accepting it.
74 #[inline]
75 fn schedule_callable<C, R, E>(&self, delay: Duration, task: C) -> Result<Self::TrackedHandle<R, E>, SubmissionError>
76 where
77 C: Callable<R, E> + Send + 'static,
78 R: Send + 'static,
79 E: Send + 'static,
80 {
81 self.schedule_callable_at(Instant::now() + delay, task)
82 }
83
84 /// Schedules a runnable task to start at a monotonic instant.
85 ///
86 /// # Parameters
87 ///
88 /// * `instant` - Monotonic instant at which the task becomes runnable.
89 /// * `task` - Runnable to execute at or after the instant.
90 ///
91 /// # Returns
92 ///
93 /// A tracked handle for observing or cancelling the scheduled task.
94 ///
95 /// # Errors
96 ///
97 /// Returns [`SubmissionError`] when the service refuses the task before
98 /// accepting it.
99 #[inline]
100 fn schedule_at<T, E>(&self, instant: Instant, task: T) -> Result<Self::TrackedHandle<(), E>, SubmissionError>
101 where
102 T: Runnable<E> + Send + 'static,
103 E: Send + 'static,
104 {
105 let mut task = task;
106 self.schedule_callable_at(instant, move || task.run())
107 }
108
109 /// Schedules a callable task to start at a monotonic instant.
110 ///
111 /// # Parameters
112 ///
113 /// * `instant` - Monotonic instant at which the task becomes runnable.
114 /// * `task` - Callable to execute at or after the instant.
115 ///
116 /// # Returns
117 ///
118 /// A tracked handle for observing or cancelling the scheduled task.
119 ///
120 /// # Errors
121 ///
122 /// Returns [`SubmissionError`] when the service refuses the task before
123 /// accepting it.
124 fn schedule_callable_at<C, R, E>(
125 &self,
126 instant: Instant,
127 task: C,
128 ) -> Result<Self::TrackedHandle<R, E>, SubmissionError>
129 where
130 C: Callable<R, E> + Send + 'static,
131 R: Send + 'static,
132 E: Send + 'static;
133}