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}