taskvisor/tasks/
task.rs

1//! # Task abstraction for supervised execution.
2//!
3//! Defines the core [`Task`] trait for async, cancelable units of work.
4//!
5//! - **[`Task`]** trait for implementing async tasks with cancellation support
6//! - **[`TaskRef`]** shared handle (`Arc<dyn Task>`) for passing tasks across the runtime
7//! - **[`BoxTaskFuture`]** type alias for boxed task futures
8//!
9//! ## Rules
10//! - The crate provides [`TaskFn`](crate::TaskFn) a function-backed implementation that wraps closures as tasks.
11//! - Tasks receive a [`CancellationToken`] and **must** observe cancellation at safe points.
12//!
13//! ## Return semantics
14//! - `Ok(())` task completed successfully (restart policy applies).
15//! - `Err(TaskError::Canceled)` cooperative shutdown (not considered a failure).
16//! - `Err(TaskError::Fail | TaskError::Timeout)` retryable failures.
17//! - `Err(TaskError::Fatal)` non-retryable, actor terminates as dead.
18
19use std::{future::Future, pin::Pin, sync::Arc};
20
21use tokio_util::sync::CancellationToken;
22
23use crate::error::TaskError;
24
25/// Boxed future returned by [`Task::spawn`].
26///
27/// This is a type alias for `Pin<Box<dyn Future<...>>>`:
28/// - **Boxed**: required for trait objects (dynamic dispatch)
29/// - **Pinned**: required for async futures (self-referential structs)
30/// - **Send**: task futures can be sent across threads
31pub type BoxTaskFuture = Pin<Box<dyn Future<Output = Result<(), TaskError>> + Send + 'static>>;
32
33/// Shared handle to a task object.
34///
35/// Type alias for `Arc<dyn Task>`, used throughout the runtime for:
36/// - Passing tasks to [`Supervisor`](crate::Supervisor)
37/// - Sharing tasks between actors
38/// - Cloning task references cheaply
39pub type TaskRef = Arc<dyn Task>;
40
41/// Asynchronous, cancelable unit of work.
42///
43/// A `Task` represents a unit of work that can be:
44/// - **Spawned multiple times** (via [`spawn`](Task::spawn))
45/// - **Cancelled cooperatively** (via [`CancellationToken`])
46/// - **Supervised** (by [`Supervisor`](crate::Supervisor))
47///
48/// ## Requirements
49/// - **Cancellation**: implementations **must** observe `ctx.cancelled()` at safe await points and
50///   return `Err(TaskError::Canceled)` promptly on shutdown.
51///
52/// ## Example
53/// ```rust
54/// use std::{future::Future, pin::Pin, time::Duration};
55/// use tokio_util::sync::CancellationToken;
56/// use taskvisor::{Task, TaskError};
57///
58/// struct MyTask;
59///
60/// impl Task for MyTask {
61///     fn name(&self) -> &str { "my-task" }
62///
63///     fn spawn(&self, ctx: CancellationToken)
64///         -> Pin<Box<dyn Future<Output = Result<(), TaskError>> + Send + 'static>>
65///     {
66///         Box::pin(async move {
67///             loop {
68///                 // Do one unit of work (replace with real IO/compute)
69///                 // Safe point with cancellation via select
70///                 tokio::select! {
71///                     _ = ctx.cancelled() => {
72///                         return Err(TaskError::Canceled);
73///                     }
74///                     _ = tokio::time::sleep(Duration::from_millis(200)) => {
75///                         // work chunk finished; continue loop
76///                     }
77///                 }
78///             }
79///         })
80///     }
81/// }
82/// ```
83pub trait Task: Send + Sync + 'static {
84    /// Returns a stable, human-readable task name.
85    ///
86    /// Used for logging, metrics, and stuck task detection during shutdown.
87    fn name(&self) -> &str;
88
89    /// Creates a new Future that runs the task until completion or cancellation.
90    ///
91    /// ### Cancellation requirements
92    /// Implementations must observe `ctx.cancelled()` at safe `await` points and return
93    /// `Err(TaskError::Canceled)` promptly upon shutdown.
94    ///
95    /// ### Stateless execution
96    /// This method takes `&self` (not `&mut self`), meaning:
97    /// - Safe to call from multiple actors concurrently
98    /// - Each call returns an independent future
99    /// - No shared mutable state between spawns
100    fn spawn(&self, ctx: CancellationToken) -> BoxTaskFuture;
101}