Skip to main content

moirai_core/executor/
spawner.rs

1//! Task spawning interface.
2
3use crate::error::ExecutorResult;
4use crate::{Priority, Task, TaskHandle};
5
6/// Core task spawning capabilities.
7///
8/// This trait provides the fundamental ability to spawn tasks for execution.
9/// It follows the Single Responsibility Principle by focusing only on task spawning.
10///
11/// # Behavior Guarantees
12/// - Task spawning is non-blocking and returns immediately
13/// - Tasks are scheduled for execution but may not start immediately
14/// - Task handles can be used to wait for completion or cancel tasks
15/// - Memory ordering follows acquire-release semantics for task state
16///
17/// # Performance Characteristics
18/// - Task spawn: O(1) amortized, < 100ns typical latency
19/// - Memory overhead: < 64 bytes per task
20/// - Thread-safe: All operations are safe for concurrent access
21pub trait TaskSpawner: Send + Sync + 'static {
22    /// Spawns a new task for execution.
23    ///
24    /// # Arguments
25    /// * `task` - The task to be executed
26    ///
27    /// # Returns
28    /// A handle to the spawned task that allows monitoring and control
29    ///
30    /// # Errors
31    /// Returns `TaskError::SpawnFailed` if the task cannot be spawned due to:
32    /// - Resource exhaustion (queue full, memory limit reached)
33    /// - Task validation failures (invalid priority, security constraints)
34    /// - System shutdown in progress
35    fn spawn<T>(&self, task: T) -> ExecutorResult<TaskHandle<T::Output>>
36    where
37        T: Task + Send + 'static;
38
39    /// Spawns an asynchronous task (Future) for execution.
40    ///
41    /// # Arguments
42    /// * `future` - The future to be executed
43    ///
44    /// # Returns
45    /// A handle to the spawned task
46    ///
47    /// # Errors
48    /// Returns `TaskError::SpawnFailed` under the same conditions as `spawn`
49    fn spawn_async<F>(&self, future: F) -> ExecutorResult<TaskHandle<F::Output>>
50    where
51        F: core::future::Future + Send + 'static,
52        F::Output: Send + 'static;
53
54    /// Spawns a blocking task that may perform I/O or CPU-intensive work.
55    ///
56    /// # Arguments
57    /// * `func` - The blocking function to execute
58    ///
59    /// # Returns
60    /// A handle to the spawned task
61    ///
62    /// # Errors
63    /// Returns `TaskError::SpawnFailed` under the same conditions as `spawn`
64    fn spawn_blocking<F, R>(&self, func: F) -> ExecutorResult<TaskHandle<R>>
65    where
66        F: FnOnce() -> R + Send + 'static,
67        R: Send + 'static;
68
69    /// Spawns a fire-and-forget task whose result is discarded.
70    ///
71    /// Unlike [`spawn_blocking`](Self::spawn_blocking), the caller receives no
72    /// handle, so an implementation can avoid the per-task
73    /// `Arc<TaskResultSlot>` heap allocation and its atomic reference counting
74    /// that result-bearing spawns require. The task is still tracked for
75    /// graceful-shutdown drain and metrics; it always runs to completion (there
76    /// is no handle to drop, so dropping is not a cancellation path).
77    ///
78    /// The provided default routes through
79    /// [`spawn_blocking`](Self::spawn_blocking) and discards the handle, so it
80    /// still allocates a result slot; implementations should override it to
81    /// skip that allocation.
82    ///
83    /// # Errors
84    /// Returns `TaskError::SpawnFailed` under the same conditions as
85    /// [`spawn`](Self::spawn).
86    fn spawn_detached<F>(&self, func: F) -> ExecutorResult<()>
87    where
88        F: FnOnce() + Send + 'static,
89    {
90        self.spawn_blocking(func).map(drop)
91    }
92
93    /// Spawns a task with specific priority and scheduling hints.
94    ///
95    /// # Arguments
96    /// * `task` - The task to be executed
97    /// * `priority` - The scheduling priority for this task
98    /// * `locality_hint` - Optional hint about preferred execution location
99    ///
100    /// # Returns
101    /// A handle to the spawned task
102    ///
103    /// # Errors
104    /// Returns `TaskError::SpawnFailed` under the same conditions as `spawn`
105    fn spawn_with_priority<T>(
106        &self,
107        task: T,
108        priority: Priority,
109        locality_hint: Option<usize>,
110    ) -> ExecutorResult<TaskHandle<T::Output>>
111    where
112        T: Task + Send + 'static;
113
114    /// Spawn a task on the current thread's local queue for better locality
115    /// (inspired by Tokio's `spawn_local`)
116    fn spawn_local<T>(&self, task: T) -> ExecutorResult<TaskHandle<T::Output>>
117    where
118        T: Task + 'static,
119    {
120        // Default implementation falls back to regular spawn
121        // Executors can override for better locality
122        self.spawn(task)
123    }
124}