TaskTracker

Struct TaskTracker 

Source
pub struct TaskTracker(/* private fields */);
Expand description

Hierarchical task tracker with pluggable scheduling and error policies

TaskTracker provides a composable system for managing background tasks with:

  • Configurable scheduling via TaskScheduler implementations
  • Flexible error handling via OnErrorPolicy implementations
  • Parent-child relationships with independent metrics
  • Cancellation propagation and isolation
  • Built-in cancellation token support

Built on top of tokio_util::task::TaskTracker for robust task lifecycle management.

§Example

// Create a task tracker with semaphore-based scheduling
let scheduler = SemaphoreScheduler::with_permits(3);
let policy = LogOnlyPolicy::new();
let root = TaskTracker::builder()
    .scheduler(scheduler)
    .error_policy(policy)
    .build()?;

// Spawn some tasks
let handle1 = root.spawn(async { Ok(1) });
let handle2 = root.spawn(async { Ok(2) });

// Get results and join all tasks
let result1 = handle1.await.unwrap().unwrap();
let result2 = handle2.await.unwrap().unwrap();
assert_eq!(result1, 1);
assert_eq!(result2, 2);

Implementations§

Source§

impl TaskTracker

Source

pub fn builder() -> TaskTrackerBuilder

Create a new root task tracker using the builder pattern

This is the preferred way to create new task trackers.

§Example
let scheduler = SemaphoreScheduler::with_permits(10);
let error_policy = LogOnlyPolicy::new();
let tracker = TaskTracker::builder()
    .scheduler(scheduler)
    .error_policy(error_policy)
    .build()?;
Source

pub fn new( scheduler: Arc<dyn TaskScheduler>, error_policy: Arc<dyn OnErrorPolicy>, ) -> Result<Self>

Create a new root task tracker with simple parameters (legacy)

This method is kept for backward compatibility. Use builder() for new code. Uses default metrics (no Prometheus integration).

§Arguments
  • scheduler - Scheduling policy to use for all tasks
  • error_policy - Error handling policy for this tracker
§Example
let scheduler = SemaphoreScheduler::with_permits(10);
let error_policy = LogOnlyPolicy::new();
let tracker = TaskTracker::new(scheduler, error_policy)?;
Source

pub fn new_with_prometheus<R: MetricsRegistry + ?Sized>( scheduler: Arc<dyn TaskScheduler>, error_policy: Arc<dyn OnErrorPolicy>, registry: &R, component_name: &str, ) -> Result<Self>

Create a new root task tracker with Prometheus metrics integration

§Arguments
  • scheduler - Scheduling policy to use for all tasks
  • error_policy - Error handling policy for this tracker
  • registry - MetricsRegistry for Prometheus integration
  • component_name - Name for this tracker component
§Example
let scheduler = SemaphoreScheduler::with_permits(10);
let error_policy = LogOnlyPolicy::new();
let tracker = TaskTracker::new_with_prometheus(
    scheduler,
    error_policy,
    registry.as_ref(),
    "main_tracker"
)?;
Source

pub fn child_tracker(&self) -> Result<TaskTracker>

Create a child tracker that inherits scheduling policy

The child tracker:

  • Gets its own independent tokio TaskTracker
  • Inherits the parent’s scheduler
  • Gets a child error policy via create_child()
  • Has hierarchical metrics that chain to parent
  • Gets a child cancellation token from the parent
  • Is independent for cancellation (child cancellation doesn’t affect parent)
§Errors

Returns an error if the parent tracker is already closed

§Example
let child_tracker = root_tracker.child_tracker()?;
// Child inherits parent's policies but has separate metrics and lifecycle
Source

pub fn spawn<F, T>(&self, future: F) -> TaskHandle<T>
where F: Future<Output = Result<T>> + Send + 'static, T: Send + 'static,

Create a child tracker builder for flexible customization

The builder allows you to customize scheduling and error policies for the child tracker. If not specified, policies are inherited from the parent.

§Example
// Custom scheduler, inherit error policy
let child1 = root_tracker.child_tracker_builder()
    .scheduler(SemaphoreScheduler::with_permits(5))
    .build().unwrap();

// Custom error policy, inherit scheduler
let child2 = root_tracker.child_tracker_builder()
    .error_policy(LogOnlyPolicy::new())
    .build().unwrap();

// Both custom
let child3 = root_tracker.child_tracker_builder()
    .scheduler(SemaphoreScheduler::with_permits(3))
    .error_policy(LogOnlyPolicy::new())
    .build().unwrap();

Spawn a new task

The task will be wrapped with scheduling and error handling logic, then executed according to the configured policies. For tasks that need to inspect cancellation tokens, use [spawn_cancellable] instead.

§Arguments
  • future - The async task to execute
§Returns

A TaskHandle that can be used to await completion and access the task’s cancellation token

§Panics

Panics if the tracker has been closed. This indicates a programming error where tasks are being spawned after the tracker lifecycle has ended.

§Example
let handle = tracker.spawn(async {
    // Your async work here
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    Ok(42)
});

// Access the task's cancellation token
let cancel_token = handle.cancellation_token();

let result = handle.await?;
Source

pub fn spawn_cancellable<F, Fut, T>(&self, task_fn: F) -> TaskHandle<T>
where F: FnMut(CancellationToken) -> Fut + Send + 'static, Fut: Future<Output = CancellableTaskResult<T>> + Send + 'static, T: Send + 'static,

Spawn a cancellable task that receives a cancellation token

This is useful for tasks that need to inspect the cancellation token and gracefully handle cancellation within their logic. The task function must return a CancellableTaskResult to properly track cancellation vs errors.

§Arguments
  • task_fn - Function that takes a cancellation token and returns a future that resolves to CancellableTaskResult<T>
§Returns

A TaskHandle that can be used to await completion and access the task’s cancellation token

§Panics

Panics if the tracker has been closed. This indicates a programming error where tasks are being spawned after the tracker lifecycle has ended.

§Example
let handle = tracker.spawn_cancellable(|cancel_token| async move {
    tokio::select! {
        _ = tokio::time::sleep(std::time::Duration::from_millis(100)) => {
            CancellableTaskResult::Ok(42)
        },
        _ = cancel_token.cancelled() => CancellableTaskResult::Cancelled,
    }
});

// Access the task's individual cancellation token
let task_cancel_token = handle.cancellation_token();

let result = handle.await?;
Source

pub fn metrics(&self) -> &dyn HierarchicalTaskMetrics

Get metrics for this tracker

Metrics are specific to this tracker and do not include metrics from parent or child trackers.

§Example
let metrics = tracker.metrics();
println!("Success: {}, Failed: {}", metrics.success(), metrics.failed());
Source

pub fn cancel(&self)

Cancel this tracker and all its tasks

This will signal cancellation to all currently running tasks and prevent new tasks from being spawned. The cancellation is immediate and forceful.

§Example
// Spawn a long-running task
let handle = tracker.spawn_cancellable(|cancel_token| async move {
    tokio::select! {
        _ = tokio::time::sleep(std::time::Duration::from_secs(10)) => {
            dynamo_runtime::utils::tasks::tracker::CancellableTaskResult::Ok(42)
        }
        _ = cancel_token.cancelled() => {
            dynamo_runtime::utils::tasks::tracker::CancellableTaskResult::Cancelled
        }
    }
}).await?;

// Cancel the tracker (and thus the task)
tracker.cancel();
Source

pub fn is_closed(&self) -> bool

Check if this tracker is closed

Source

pub fn cancellation_token(&self) -> CancellationToken

Get the cancellation token for this tracker

This allows external code to observe or trigger cancellation of this tracker.

§Example
let token = tracker.cancellation_token();
// Can check cancellation state or cancel manually
if !token.is_cancelled() {
    token.cancel();
}
Source

pub fn child_count(&self) -> usize

Get the number of active child trackers

This counts only child trackers that are still alive (not dropped). Dropped child trackers are automatically cleaned up.

§Example
let child_count = tracker.child_count();
println!("This tracker has {} active children", child_count);
Source

pub fn child_tracker_builder(&self) -> ChildTrackerBuilder<'_>

Create a child tracker builder with custom configuration

This provides fine-grained control over child tracker creation, allowing you to override the scheduler or error policy while maintaining the parent-child relationship.

§Example
// Custom scheduler, inherit error policy
let child1 = parent.child_tracker_builder()
    .scheduler(SemaphoreScheduler::with_permits(5))
    .build().unwrap();

// Custom error policy, inherit scheduler
let child2 = parent.child_tracker_builder()
    .error_policy(LogOnlyPolicy::new())
    .build().unwrap();

// Inherit both policies from parent
let child3 = parent.child_tracker_builder()
    .build().unwrap();
Source

pub async fn join(&self)

Join this tracker and all child trackers

This method gracefully shuts down the entire tracker hierarchy by:

  1. Closing all trackers (preventing new task spawning)
  2. Waiting for all existing tasks to complete

Uses stack-safe traversal to prevent stack overflow in deep hierarchies. Children are processed before parents to ensure proper shutdown order.

Hierarchical Behavior:

  • Processes children before parents to ensure proper shutdown order
  • Each tracker is closed before waiting (Tokio requirement)
  • Leaf trackers simply close and wait for their own tasks
§Example
tracker.join().await;

Trait Implementations§

Source§

impl Clone for TaskTracker

Source§

fn clone(&self) -> TaskTracker

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Paint for T
where T: ?Sized,

Source§

fn fg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the foreground set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like red() and green(), which have the same functionality but are pithier.

§Example

Set foreground color to white using fg():

use yansi::{Paint, Color};

painted.fg(Color::White);

Set foreground color to white using white().

use yansi::Paint;

painted.white();
Source§

fn primary(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Primary].

§Example
println!("{}", value.primary());
Source§

fn fixed(&self, color: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Fixed].

§Example
println!("{}", value.fixed(color));
Source§

fn rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Rgb].

§Example
println!("{}", value.rgb(r, g, b));
Source§

fn black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Black].

§Example
println!("{}", value.black());
Source§

fn red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Red].

§Example
println!("{}", value.red());
Source§

fn green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Green].

§Example
println!("{}", value.green());
Source§

fn yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Yellow].

§Example
println!("{}", value.yellow());
Source§

fn blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Blue].

§Example
println!("{}", value.blue());
Source§

fn magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Magenta].

§Example
println!("{}", value.magenta());
Source§

fn cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Cyan].

§Example
println!("{}", value.cyan());
Source§

fn white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: White].

§Example
println!("{}", value.white());
Source§

fn bright_black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlack].

§Example
println!("{}", value.bright_black());
Source§

fn bright_red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightRed].

§Example
println!("{}", value.bright_red());
Source§

fn bright_green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightGreen].

§Example
println!("{}", value.bright_green());
Source§

fn bright_yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightYellow].

§Example
println!("{}", value.bright_yellow());
Source§

fn bright_blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlue].

§Example
println!("{}", value.bright_blue());
Source§

fn bright_magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.bright_magenta());
Source§

fn bright_cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightCyan].

§Example
println!("{}", value.bright_cyan());
Source§

fn bright_white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightWhite].

§Example
println!("{}", value.bright_white());
Source§

fn bg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the background set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like on_red() and on_green(), which have the same functionality but are pithier.

§Example

Set background color to red using fg():

use yansi::{Paint, Color};

painted.bg(Color::Red);

Set background color to red using on_red().

use yansi::Paint;

painted.on_red();
Source§

fn on_primary(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Primary].

§Example
println!("{}", value.on_primary());
Source§

fn on_fixed(&self, color: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Fixed].

§Example
println!("{}", value.on_fixed(color));
Source§

fn on_rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Rgb].

§Example
println!("{}", value.on_rgb(r, g, b));
Source§

fn on_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Black].

§Example
println!("{}", value.on_black());
Source§

fn on_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Red].

§Example
println!("{}", value.on_red());
Source§

fn on_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Green].

§Example
println!("{}", value.on_green());
Source§

fn on_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Yellow].

§Example
println!("{}", value.on_yellow());
Source§

fn on_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Blue].

§Example
println!("{}", value.on_blue());
Source§

fn on_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Magenta].

§Example
println!("{}", value.on_magenta());
Source§

fn on_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Cyan].

§Example
println!("{}", value.on_cyan());
Source§

fn on_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: White].

§Example
println!("{}", value.on_white());
Source§

fn on_bright_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlack].

§Example
println!("{}", value.on_bright_black());
Source§

fn on_bright_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightRed].

§Example
println!("{}", value.on_bright_red());
Source§

fn on_bright_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightGreen].

§Example
println!("{}", value.on_bright_green());
Source§

fn on_bright_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightYellow].

§Example
println!("{}", value.on_bright_yellow());
Source§

fn on_bright_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlue].

§Example
println!("{}", value.on_bright_blue());
Source§

fn on_bright_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.on_bright_magenta());
Source§

fn on_bright_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightCyan].

§Example
println!("{}", value.on_bright_cyan());
Source§

fn on_bright_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightWhite].

§Example
println!("{}", value.on_bright_white());
Source§

fn attr(&self, value: Attribute) -> Painted<&T>

Enables the styling Attribute value.

This method should be used rarely. Instead, prefer to use attribute-specific builder methods like bold() and underline(), which have the same functionality but are pithier.

§Example

Make text bold using attr():

use yansi::{Paint, Attribute};

painted.attr(Attribute::Bold);

Make text bold using using bold().

use yansi::Paint;

painted.bold();
Source§

fn bold(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Bold].

§Example
println!("{}", value.bold());
Source§

fn dim(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Dim].

§Example
println!("{}", value.dim());
Source§

fn italic(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Italic].

§Example
println!("{}", value.italic());
Source§

fn underline(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Underline].

§Example
println!("{}", value.underline());

Returns self with the attr() set to [Attribute :: Blink].

§Example
println!("{}", value.blink());

Returns self with the attr() set to [Attribute :: RapidBlink].

§Example
println!("{}", value.rapid_blink());
Source§

fn invert(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Invert].

§Example
println!("{}", value.invert());
Source§

fn conceal(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Conceal].

§Example
println!("{}", value.conceal());
Source§

fn strike(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Strike].

§Example
println!("{}", value.strike());
Source§

fn quirk(&self, value: Quirk) -> Painted<&T>

Enables the yansi Quirk value.

This method should be used rarely. Instead, prefer to use quirk-specific builder methods like mask() and wrap(), which have the same functionality but are pithier.

§Example

Enable wrapping using .quirk():

use yansi::{Paint, Quirk};

painted.quirk(Quirk::Wrap);

Enable wrapping using wrap().

use yansi::Paint;

painted.wrap();
Source§

fn mask(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Mask].

§Example
println!("{}", value.mask());
Source§

fn wrap(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Wrap].

§Example
println!("{}", value.wrap());
Source§

fn linger(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Linger].

§Example
println!("{}", value.linger());
Source§

fn clear(&self) -> Painted<&T>

👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear(). The clear() method will be removed in a future release.

Returns self with the quirk() set to [Quirk :: Clear].

§Example
println!("{}", value.clear());
Source§

fn resetting(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Resetting].

§Example
println!("{}", value.resetting());
Source§

fn bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Bright].

§Example
println!("{}", value.bright());
Source§

fn on_bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: OnBright].

§Example
println!("{}", value.on_bright());
Source§

fn whenever(&self, value: Condition) -> Painted<&T>

Conditionally enable styling based on whether the Condition value applies. Replaces any previous condition.

See the crate level docs for more details.

§Example

Enable styling painted only when both stdout and stderr are TTYs:

use yansi::{Paint, Condition};

painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
Source§

fn new(self) -> Painted<Self>
where Self: Sized,

Create a new Painted with a default Style. Read more
Source§

fn paint<S>(&self, style: S) -> Painted<&Self>
where S: Into<Style>,

Apply a style wholesale to self. Any previous style is replaced. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> Data for T
where T: Send + Sync + 'static,

Source§

impl<T> ErasedDestructor for T
where T: 'static,