aa1cad4422
* Idea for transparent ShutdownManager use * Tracker hierarchies * Fix wasm shutdown, convinience shutdown method
171 lines
5.7 KiB
Rust
171 lines
5.7 KiB
Rust
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
use crate::event::SentStatus;
|
|
use std::future::Future;
|
|
use tokio_util::sync::{
|
|
CancellationToken, DropGuard, WaitForCancellationFuture, WaitForCancellationFutureOwned,
|
|
};
|
|
use tracing::warn;
|
|
|
|
/// A wrapped [CancellationToken](tokio_util::sync::CancellationToken) that is used for
|
|
/// signalling and listening for cancellation requests.
|
|
// We don't use CancellationToken in case we wanted to include additional fields/methods
|
|
// down the line.
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct ShutdownToken {
|
|
inner: CancellationToken,
|
|
}
|
|
|
|
impl From<CancellationToken> for ShutdownToken {
|
|
fn from(inner: CancellationToken) -> Self {
|
|
ShutdownToken { inner }
|
|
}
|
|
}
|
|
|
|
impl ShutdownToken {
|
|
/// A drop in no-op replacement for `send_status_msg` for easier migration from [TaskClient](crate::TaskClient).
|
|
#[deprecated]
|
|
#[track_caller]
|
|
pub fn send_status_msg(&self, status: SentStatus) {
|
|
let caller = std::panic::Location::caller();
|
|
warn!("{caller} attempted to send {status} - there are no more listeners of those");
|
|
}
|
|
|
|
/// Creates a new ShutdownToken in the non-cancelled state.
|
|
pub fn new() -> Self {
|
|
ShutdownToken {
|
|
inner: CancellationToken::new(),
|
|
}
|
|
}
|
|
|
|
/// Creates a new ShutdownToken given a tokio `CancellationToken`.
|
|
pub fn new_from_tokio_token(cancellation_token: CancellationToken) -> Self {
|
|
ShutdownToken {
|
|
inner: cancellation_token,
|
|
}
|
|
}
|
|
|
|
/// Gets reference to the underlying [CancellationToken](tokio_util::sync::CancellationToken).
|
|
pub fn inner(&self) -> &CancellationToken {
|
|
&self.inner
|
|
}
|
|
|
|
/// Get an owned [CancellationToken](tokio_util::sync::CancellationToken) for public API use.
|
|
/// This is useful when you need to expose cancellation to SDK users without
|
|
/// exposing the internal ShutdownToken type.
|
|
pub fn to_cancellation_token(&self) -> CancellationToken {
|
|
self.inner.clone()
|
|
}
|
|
|
|
/// Creates a `ShutdownToken` which will get cancelled whenever the
|
|
/// current token gets cancelled. Unlike a cloned `ShutdownToken`,
|
|
/// cancelling a child token does not cancel the parent token.
|
|
///
|
|
/// If the current token is already cancelled, the child token will get
|
|
/// returned in cancelled state.
|
|
pub fn child_token(&self) -> ShutdownToken {
|
|
ShutdownToken {
|
|
inner: self.inner.child_token(),
|
|
}
|
|
}
|
|
|
|
/// Cancel the underlying [CancellationToken](tokio_util::sync::CancellationToken) and all child tokens which had been
|
|
/// derived from it.
|
|
///
|
|
/// This will wake up all tasks which are waiting for cancellation.
|
|
pub fn cancel(&self) {
|
|
self.inner.cancel();
|
|
}
|
|
|
|
/// Returns `true` if the underlying [CancellationToken](tokio_util::sync::CancellationToken) is cancelled.
|
|
pub fn is_cancelled(&self) -> bool {
|
|
self.inner.is_cancelled()
|
|
}
|
|
|
|
/// Returns a `Future` that gets fulfilled when cancellation is requested.
|
|
///
|
|
/// The future will complete immediately if the token is already cancelled
|
|
/// when this method is called.
|
|
///
|
|
/// # Cancel safety
|
|
///
|
|
/// This method is cancel safe.
|
|
pub fn cancelled(&self) -> WaitForCancellationFuture<'_> {
|
|
self.inner.cancelled()
|
|
}
|
|
|
|
/// Returns a `Future` that gets fulfilled when cancellation is requested.
|
|
///
|
|
/// The future will complete immediately if the token is already cancelled
|
|
/// when this method is called.
|
|
///
|
|
/// The function takes self by value and returns a future that owns the
|
|
/// token.
|
|
///
|
|
/// # Cancel safety
|
|
///
|
|
/// This method is cancel safe.
|
|
pub fn cancelled_owned(self) -> WaitForCancellationFutureOwned {
|
|
self.inner.cancelled_owned()
|
|
}
|
|
|
|
/// Creates a `ShutdownDropGuard` for this token.
|
|
///
|
|
/// Returned guard will cancel this token (and all its children) on drop
|
|
/// unless disarmed.
|
|
pub fn drop_guard(self) -> ShutdownDropGuard {
|
|
ShutdownDropGuard {
|
|
inner: self.inner.drop_guard(),
|
|
}
|
|
}
|
|
|
|
/// Runs a future to completion and returns its result wrapped inside an `Option`
|
|
/// unless the `ShutdownToken` is cancelled. In that case the function returns
|
|
/// `None` and the future gets dropped.
|
|
///
|
|
/// # Cancel safety
|
|
///
|
|
/// This method is only cancel safe if `fut` is cancel safe.
|
|
pub async fn run_until_cancelled<F>(&self, fut: F) -> Option<F::Output>
|
|
where
|
|
F: Future,
|
|
{
|
|
self.inner.run_until_cancelled(fut).await
|
|
}
|
|
|
|
/// Runs a future to completion and returns its result wrapped inside an `Option`
|
|
/// unless the `ShutdownToken` is cancelled. In that case the function returns
|
|
/// `None` and the future gets dropped.
|
|
///
|
|
/// The function takes self by value and returns a future that owns the token.
|
|
///
|
|
/// # Cancel safety
|
|
///
|
|
/// This method is only cancel safe if `fut` is cancel safe.
|
|
pub async fn run_until_cancelled_owned<F>(self, fut: F) -> Option<F::Output>
|
|
where
|
|
F: Future,
|
|
{
|
|
self.inner.run_until_cancelled_owned(fut).await
|
|
}
|
|
}
|
|
|
|
/// A wrapper for [DropGuard](tokio_util::sync::DropGuard) that wraps around a cancellation token
|
|
/// which automatically cancels it on drop.
|
|
/// It is created using `drop_guard` method on the `ShutdownToken`.
|
|
pub struct ShutdownDropGuard {
|
|
inner: DropGuard,
|
|
}
|
|
|
|
impl ShutdownDropGuard {
|
|
/// Returns stored [ShutdownToken](ShutdownToken) and removes this drop guard instance
|
|
/// (i.e. it will no longer cancel token). Other guards for this token
|
|
/// are not affected.
|
|
pub fn disarm(self) -> ShutdownToken {
|
|
ShutdownToken {
|
|
inner: self.inner.disarm(),
|
|
}
|
|
}
|
|
}
|