Skip to main content

Crate soft_cycle

Crate soft_cycle 

Source
Expand description

§soft-cycle

Crates.io docs.rs License: MIT CI

A small async Rust crate for coordinating soft restarts and graceful shutdowns around a shared SoftCycleController, designed for async runtimes where many tasks need to observe lifecycle transitions without blocking:

  • try_notify(payload) publishes a lifecycle notification and wakes current listeners, with an optional payload.
  • try_clear() transitions the controller back to the non-notified state.
  • listener() returns a future that resolves when being notified with the observed payload.

§Usage

Use SoftCycleController::new to create a new controller instance. Call try_notify to publish a notification with a payload and get Ok(sequence_number) on success (or Err(payload) if already notified), where sequence_number is a monotonically increasing number starting from 0. Call try_clear to clear the notified state and get Ok(sequence_number) for the cleared notification (or Err(()) if not currently notified). Call listener to create a SoftCycleListener future that resolves with Ok(payload) when a notification is observed.

§Guarantees

  • Linearizable order: All try_notify and try_clear operations are linearizable with respect to a single global order.
  • Non-blocking: try_notify and try_clear are synchronous and never block.
  • Listener completion: A listener created after a notification and before the next clearance completes immediately with the current payload. A listener created after a clear and before the next notification completes in a finite number of polls (usually one) after the next try_notify. If multiple notify/clear cycles occur after a listener is created, it returns one of those payloads (no guarantee of returning the earliest or latest); this is a rare scenario and is not likely to happen unless try_notify and try_clear are called multiple times in a very short time frame.

§Features

  • global_instance (default): Enables a process-wide default controller and the async free functions get_lifetime_controller, try_restart, try_shutdown, listener, and clear at the crate root. The global controller uses SoftCycleMessage as the payload type, which contains Shutdown and Restart variants.

§Example

use soft_cycle::{SoftCycleController, SoftCycleMessage};
use std::sync::Arc;
use tokio::time::{sleep, Duration, timeout};

#[tokio::main]
async fn main() {
    let controller = Arc::new(SoftCycleController::<SoftCycleMessage>::new());

    // Worker that reacts to notifications.
    let worker_controller = controller.clone();
    let worker = tokio::spawn(async move {
        loop {
            let payload = worker_controller.listener().await.unwrap();
            match payload {
                SoftCycleMessage::Shutdown => {
                    println!("worker: shutdown");
                    break;
                }
                SoftCycleMessage::Restart => {
                    println!("worker: restart");
                }
            }
        }
    });

    // Producer notifies restart.
    assert_eq!(controller.try_notify(SoftCycleMessage::Restart), Ok(0));
    // Already notified, returns Err.
    assert_eq!(controller.try_notify(SoftCycleMessage::Restart), Err(SoftCycleMessage::Restart));
    // Clear when restart handling phase is done.
    assert_eq!(controller.try_clear(), Ok(0));
    // Already cleared, returns Err.
    assert_eq!(controller.try_clear(), Err(()));

    sleep(Duration::from_millis(100)).await;

    // Producer notifies restart again.
    assert_eq!(controller.try_notify(SoftCycleMessage::Restart), Ok(1));
    // Clear when restart handling phase is done.
    assert_eq!(controller.try_clear(), Ok(1));

    sleep(Duration::from_millis(100)).await;

    // Producer notifies shutdown.
    assert_eq!(controller.try_notify(SoftCycleMessage::Shutdown), Ok(2));
    // Optional: wait for worker to observe shutdown.
    timeout(Duration::from_secs(2), worker).await.unwrap().unwrap();
}

Modules§

payload
Atomic payload types and the Payload trait for use with crate::SoftCycleController.

Structs§

SoftCycleController
Coordination controller for soft restarts and graceful shutdowns.
SoftCycleListener
Future that completes when a notification from the associated controller is observed.

Enums§

SoftCycleMessageglobal_instance
Message type for the global controller.

Traits§

Payload
Trait for payload types that can be stored and loaded atomically by the SoftCycleController.

Functions§

clearglobal_instance
Clears the notified state on the global controller.
get_lifetime_controllerglobal_instance
Returns a reference to the global SoftCycleController, initializing it on first call.
listenerglobal_instance
Listener on the global controller.
try_restartglobal_instance
Attempts to notify a restart on the global controller.
try_shutdownglobal_instance
Attempts to notify a shutdown on the global controller.