Expand description
§soft-cycle
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_notifyandtry_clearoperations are linearizable with respect to a single global order. - Non-blocking:
try_notifyandtry_clearare 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 unlesstry_notifyandtry_clearare called multiple times in a very short time frame.
§Features
global_instance(default): Enables a process-wide default controller and the async free functionsget_lifetime_controller,try_restart,try_shutdown,listener, andclearat the crate root. The global controller usesSoftCycleMessageas the payload type, which containsShutdownandRestartvariants.
§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
Payloadtrait for use withcrate::SoftCycleController.
Structs§
- Soft
Cycle Controller - Coordination controller for soft restarts and graceful shutdowns.
- Soft
Cycle Listener - Future that completes when a notification from the associated controller is observed.
Enums§
- Soft
Cycle Message global_instance - Message type for the global controller.
Traits§
- Payload
- Trait for payload types that can be stored and loaded atomically by the
SoftCycleController.
Functions§
- clear
global_instance - Clears the notified state on the global controller.
- get_
lifetime_ controller global_instance - Returns a reference to the global
SoftCycleController, initializing it on first call. - listener
global_instance - Listener on the global controller.
- try_
restart global_instance - Attempts to notify a restart on the global controller.
- try_
shutdown global_instance - Attempts to notify a shutdown on the global controller.