spry 0.0.4

Resilient, self-healing async process hierarchies in the style of Erlang/OTP
Documentation
//! Types for signaling processes to settle, shut down, and terminate.

use tokio_util::sync::{CancellationToken, DropGuard};

/// A token representing a signal to a process to "settle", i.e. cease operations, clean up, and
/// terminate normally. Settlement is a cooperative process, and the process must be designed to
/// listen to this signal.
///
/// A major design principle of `spry` is that processes which fail to settle in a timely manner
/// are forcibly cancelled/aborted.
#[derive(Clone, Debug)]
pub struct SettlingToken(CancellationToken);

impl SettlingToken {
  /// Waits for a settlement signal.
  pub async fn settled(&self) {
    self.0.cancelled().await
  }

  /// Returns true if the token has been settled.
  pub fn is_settled(&self) -> bool {
    self.0.is_cancelled()
  }

  pub(crate) fn new() -> Self {
    Self(CancellationToken::new())
  }

  pub(crate) fn signal_settlement(&self) {
    self.0.cancel()
  }

  pub(crate) fn into_shutdown_token(self) -> ShutdownToken {
    ShutdownToken(self.0)
  }
}

/// A token representing a signal that a process should be shut down. This implies that `spry` will
/// first attempt to settle the process and then forcibly abort if timely settlement fails.
#[derive(Clone, Debug)]
pub struct ShutdownToken(pub(crate) CancellationToken);

impl ShutdownToken {
  /// Triggers this shutdown signal, causing its process to be settled and then forcibly aborted.
  pub fn signal_shutdown(&self) {
    self.0.cancel()
  }

  pub fn guard(self) -> ShutdownGuard {
    ShutdownGuard(self.0.drop_guard())
  }

  pub(crate) fn new() -> Self {
    Self(CancellationToken::new())
  }
}

/// A type guarding a shutdown signal. If this type is dropped without being disarmed then the
/// backing signal will be triggered.
pub struct ShutdownGuard(DropGuard);

impl ShutdownGuard {
  /// Disarms this guard, preventing the shutdown signal from being triggered.
  pub fn disarm(self) -> ShutdownToken {
    ShutdownToken(self.0.disarm())
  }
}

/// A token representing a signal that a process has fully terminated.
#[derive(Clone, Debug)]
pub struct TerminationToken(CancellationToken);

impl TerminationToken {
  pub async fn terminated(&self) {
    self.0.cancelled().await
  }

  pub fn is_terminated(&self) -> bool {
    self.0.is_cancelled()
  }

  pub(crate) fn new() -> Self {
    Self(CancellationToken::new())
  }

  pub(crate) fn signal_termination(&self) {
    self.0.cancel()
  }
}