forked from
smokesignal.events/quickdid
QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with Redis-backed caching and queue processing.
1//! Task management utilities for consistent background task handling
2//!
3//! This module provides helpers for spawning and managing background tasks with:
4//! - Consistent start/stop logging
5//! - Automatic shutdown on task failure
6//! - Graceful shutdown support
7
8use std::future::Future;
9use tokio_util::{sync::CancellationToken, task::TaskTracker};
10use tracing::{error, info};
11
12/// Spawn a background task with cancellation support
13///
14/// This version allows the task to be cancelled via the token and handles
15/// both graceful shutdown and unexpected failures
16pub fn spawn_cancellable_task<F, Fut>(
17 tracker: &TaskTracker,
18 app_token: CancellationToken,
19 task_name: &str,
20 task_builder: F,
21) where
22 F: FnOnce(CancellationToken) -> Fut + Send + 'static,
23 Fut: Future<Output = anyhow::Result<()>> + Send + 'static,
24{
25 info!(task = task_name, "Starting cancellable background task");
26
27 let task_token = app_token.clone();
28 let cancel_token = app_token.clone();
29
30 let inner_task_name = task_name.to_string();
31
32 tracker.spawn(async move {
33 tokio::select! {
34 result = task_builder(cancel_token.clone()) => {
35 match result {
36 Ok(()) => {
37 info!(task = inner_task_name, "Background task completed successfully");
38 }
39 Err(e) => {
40 error!(error = ?e, task = inner_task_name, "Background task failed unexpectedly");
41 // Trigger application shutdown on task failure
42 task_token.cancel();
43 }
44 }
45 }
46 () = task_token.cancelled() => {
47 info!(task = inner_task_name, "Background task shutting down gracefully");
48 }
49 }
50 });
51}
52
53/// Macro for consistent task error handling within a task
54#[macro_export]
55macro_rules! task_try {
56 ($expr:expr, $task_name:expr) => {
57 match $expr {
58 Ok(val) => val,
59 Err(e) => {
60 tracing::error!(task = $task_name, error = ?e, "Task operation failed");
61 return Err(e.into());
62 }
63 }
64 };
65}
66
67/// Macro for logging task checkpoints
68#[macro_export]
69macro_rules! task_checkpoint {
70 ($task_name:expr, $checkpoint:expr) => {
71 tracing::debug!(
72 task = $task_name,
73 checkpoint = $checkpoint,
74 "Task checkpoint reached"
75 );
76 };
77}