axum_tasks/
lib.rs

1//! # Axum Background Tasks
2//!
3//! Production-ready background task system for Axum applications.
4//!
5//! ## Quick Start
6//!
7//! ```rust
8//! use axum::{Router, routing::post};
9//! use axum_background_tasks::{AppTasks, Task, TaskResult, admin_routes, HasTasks};
10//! use serde::{Serialize, Deserialize};
11//!
12//! #[derive(Task, Serialize, Deserialize)]
13//! #[task(description = "Processing data", retry = true)]
14//! struct DataProcessing {
15//!     data_id: String,
16//! }
17//!
18//! impl DataProcessing {
19//!     pub async fn execute(&self) -> TaskResult {
20//!         // Your task logic here
21//!         TaskResult::Success("autosave data".to_string())
22//!     }
23//! }
24//!
25//! #[derive(HasTasks)]
26//! struct AppState {
27//!     tasks: AppTasks,
28//! }
29//!
30//! #[tokio::main]
31//! async fn main() {
32//!     let app_state = AppState {
33//!         tasks: AppTasks::new(),
34//!     };
35//!     
36//!     let app = Router::new()
37//!         .route("/process", post(process_handler))
38//!         .nest("/admin", admin_routes::<AppState>())
39//!         .with_state(app_state);
40//!         
41//!     // Start workers and server
42//! }
43//! ```
44
45mod app_tasks;
46mod metrics;
47mod routes;
48mod types;
49mod worker;
50
51pub use app_tasks::{AppTasks, TaskQueueError};
52pub use metrics::TaskMetrics;
53pub use routes::admin_routes;
54pub use types::*;
55pub use worker::spawn_task_workers;
56
57pub use async_trait::async_trait;
58pub use axum_tasks_derive::{HasTasks, Task};
59pub use inventory;
60pub use tokio_util::sync::CancellationToken;
61
62#[async_trait]
63pub trait TaskHandler: Send + Sync {
64    async fn handle(&self, app_tasks: &AppTasks, job_id: &str) -> TaskResult;
65    fn description(&self) -> String;
66    fn is_retryable(&self, error: &str) -> bool;
67}
68
69pub trait HasTasks {
70    fn tasks(&self) -> &AppTasks;
71    fn tasks_mut(&mut self) -> &mut AppTasks;
72}
73
74pub type TaskFuture<'a> =
75    std::pin::Pin<Box<dyn Future<Output = Result<TaskResult, TaskResult>> + Send + 'a>>;
76pub type TaskHandlerT = for<'a> fn(&'a [u8], &'a AppTasks, &str) -> TaskFuture<'a>;
77
78pub struct TaskRegistration {
79    pub name: &'static str,
80    pub handler: TaskHandlerT,
81}
82
83inventory::collect!(TaskRegistration);
84
85pub fn init_task_system() -> (AppTasks, CancellationToken) {
86    let app_tasks = AppTasks::new();
87    let shutdown_token = CancellationToken::new();
88
89    (app_tasks, shutdown_token)
90}
91
92pub fn init_task_system_with_persistence<F>(
93    persistence_callback: F,
94) -> (AppTasks, CancellationToken)
95where
96    F: Fn(&std::collections::HashMap<String, TaskState>) + Send + Sync + 'static,
97{
98    let app_tasks = AppTasks::new().with_auto_persist(persistence_callback);
99    let shutdown_token = CancellationToken::new();
100
101    (app_tasks, shutdown_token)
102}