soft-cycle 0.1.0

Async controller for coordinating soft restarts and graceful shutdowns with shared listeners
Documentation
  • Coverage
  • 100%
    14 out of 14 items documented1 out of 9 items with examples
  • Size
  • Source code size: 21.13 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.8 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 15s Average build duration of successful builds.
  • all releases: 17s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • GeminiLab/soft-cycle
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • aarkegz

soft-cycle

A small async Rust crate for coordinating soft restarts and graceful shutdowns using a shared controller. Tasks can wait on a listener and react when a restart or shutdown is triggered.

Usage

Use [SoftCycleController::new] to create a new controller instance. Use try_restart and try_shutdown to trigger a restart or shutdown respectively. Only the first call to either method will succeed until the controller is cleared via clear. Use the listener method to be notified when a restart or shutdown is triggered.

Notice

If listener is called while the controller is already in a triggered state, it will resolve on the next trigger, not the current one.

Currently, shutdowns and restarts are only distinguishable by the boolean returned by the listener: true for shutdown, false for restart. They have no other differing behavior.

Features

  • global_instance (default): Enables a process-wide default controller and the free functions [get_lifetime_controller], [try_restart], [try_shutdown], [listener], and [clear] at the crate root.

Example

use std::sync::Arc;

use soft_cycle::SoftCycleController;
use tokio::time::{sleep, Duration};

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

    // Spawn a task to trigger a restart or shutdown
    let controller_clone = controller.clone();
    tokio::spawn(async move {
        // Simulate some external event triggering a restart
        sleep(Duration::from_secs(2)).await;
        assert!(controller_clone.try_restart().await);
        controller_clone.clear();
        // Simulate some external event triggering a shutdown
        sleep(Duration::from_secs(2)).await;
        assert!(controller_clone.try_shutdown().await);
    });

    // Simulate another working task
    let controller_clone = controller.clone();
    tokio::spawn(async move {
        loop {
            println!("Worker is doing some work...");

            tokio::select! {
                _ = sleep(Duration::from_millis(500)) => {},
                is_shutdown = controller_clone.listener() => {
                    if is_shutdown {
                        println!("Worker received shutdown signal.");
                        break;
                    } else {
                        println!("Worker received restart signal.");
                    }
                }
            }
        }
    });

    // Do something while waiting for the trigger: increment a counter and
    // print it every 200 milliseconds
    let mut counter = 0;
    loop {
        tokio::select! {
            _ = sleep(Duration::from_millis(200)) => {
                counter += 1;
                println!("Main loop counter: {}", counter);
            }
            is_shutdown = controller.listener() => {
                if is_shutdown {
                    println!("Main loop received shutdown signal.");
                    break;
                } else {
                    println!("Main loop received restart signal.");
                    // Reset counter on restart
                    counter = 0;
                }
            }
        }
    }
}