moirai_executor/hybrid/
manager.rs1use std::sync::Arc;
2
3use moirai_core::{
4 error::{ExecutorError, ExecutorResult, TaskError},
5 executor::{TaskManager, TaskStats, TaskStatus},
6 task::TaskId,
7};
8
9use super::HybridExecutor;
10use crate::registry::CancelOutcome;
11use crate::schedule::WorkScheduler;
12use crate::task::TaskMetadata;
13
14fn status_of(metadata: &TaskMetadata) -> TaskStatus {
16 if metadata.cancelled {
17 TaskStatus::Cancelled
18 } else if metadata.completed_at.is_some() {
19 TaskStatus::Completed
20 } else if metadata.started_at.is_some() {
21 TaskStatus::Running
22 } else {
23 TaskStatus::Queued
24 }
25}
26
27impl<S: WorkScheduler> TaskManager for HybridExecutor<S> {
28 fn cancel_task(&self, id: TaskId) -> ExecutorResult<()> {
37 match self.task_registry.request_cancel(id.0) {
38 Some(CancelOutcome::Requested | CancelOutcome::AlreadyCompleted) => Ok(()),
39 None => Err(ExecutorError::SpawnFailed(TaskError::InvalidOperation)),
40 }
41 }
42
43 fn task_status(&self, id: TaskId) -> Option<TaskStatus> {
44 self.task_registry
45 .get_metadata(id.0)
46 .map(|metadata| status_of(&metadata))
47 }
48
49 fn wait_for_task(
60 &self,
61 id: TaskId,
62 timeout: Option<core::time::Duration>,
63 ) -> impl core::future::Future<Output = ExecutorResult<()>> + Send {
64 let registry = Arc::clone(&self.task_registry);
65 let deadline = timeout.and_then(|timeout| std::time::Instant::now().checked_add(timeout));
66
67 std::future::poll_fn(move |context| {
68 match registry.completion(id.0) {
69 Some(true) => return std::task::Poll::Ready(Ok(())),
70 Some(false) => {}
71 None => {
72 return std::task::Poll::Ready(Err(ExecutorError::SpawnFailed(
73 TaskError::InvalidOperation,
74 )));
75 }
76 }
77 if deadline.is_some_and(|deadline| std::time::Instant::now() >= deadline) {
78 return std::task::Poll::Ready(Err(ExecutorError::SpawnFailed(TaskError::Timeout)));
79 }
80
81 registry.register_waker(id.0, context.waker());
82 if registry.is_completed(id.0) {
86 return std::task::Poll::Ready(Ok(()));
87 }
88
89 std::task::Poll::Pending
90 })
91 }
92
93 fn task_stats(&self, id: TaskId) -> Option<TaskStats> {
98 self.task_registry
99 .get_metadata(id.0)
100 .map(|metadata| TaskStats {
101 id,
102 priority: metadata.priority,
103 status: status_of(&metadata),
104 spawn_time: metadata.created_at,
105 start_time: metadata.started_at,
106 completion_time: metadata.completed_at,
107 cpu_time_ns: metadata
108 .execution_duration()
109 .map_or(0, |duration| duration.as_nanos() as u64),
110 })
111 }
112}