libdd-shared-runtime 4.0.0

Shared tokio runtime with fork-safe worker management for Datadog libraries
Documentation
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
// SPDX-License-Identifier: Apache-2.0

use async_trait::async_trait;
use libdd_capabilities::MaybeSend;

/// A background worker meant to be spawned on a [`SharedRuntime`](crate::SharedRuntime).
///
/// # Lifecycle
/// The worker's [`run`](Self::run) method is executed every time [`trigger`](Self::trigger)
/// returns. On startup [`initial_trigger`](Self::initial_trigger) is called before the first
/// [`run`](Self::run).
///
/// # Cancellation safety
/// The `trigger` function can be interrupted at any yield point (`.await`ed call). The state of the
/// worker at this point will be saved and used to restart the worker. To be able to safely restart,
/// the worker must be in a valid state on every call to `.await` within the trigger function.
/// See [`tokio::select#cancellation-safety`] for more details.
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait Worker: std::fmt::Debug + MaybeSend {
    /// Main worker function
    ///
    /// Code in this function must always use timeout on long-running await calls to avoid
    /// blocking forks if an await call takes too long to complete.
    async fn run(&mut self);

    /// Function called between each `run` to wait for the next run.
    /// This function should be cancellation safe as it can be cancelled at any yield point.
    async fn trigger(&mut self);

    /// Alternative trigger called on start to provide custom behavior.
    /// Defaults to `trigger` behavior.
    async fn initial_trigger(&mut self) {
        self.trigger().await
    }

    /// Reset the worker state. Called in the child after a fork to cleanup parent state.
    fn reset(&mut self) {}

    /// Hook called when the app is shutting down. Can be used to flush remaining data.
    async fn shutdown(&mut self) {}
}

// Blanket implementation for boxed trait objects
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl Worker for Box<dyn Worker + Sync> {
    async fn run(&mut self) {
        (**self).run().await
    }

    async fn trigger(&mut self) {
        (**self).trigger().await
    }

    async fn initial_trigger(&mut self) {
        (**self).initial_trigger().await
    }

    fn reset(&mut self) {
        (**self).reset()
    }

    async fn shutdown(&mut self) {
        (**self).shutdown().await
    }
}