Crate swansong

source ·
Expand description

§🦢 A graceful shutdown

§How this crate works

Each Swansong represents a functional unit of behavior that needs to coordinate termination. The primary type Swansong provides the control interface.

To allow Swansong to interrupt/cancel/seal various types, use Swansong::interrupt. Interrupt<T> has custom implementations of Future, Stream, [AsyncRead][futures_io::AsyncRead], [AsyncWrite][futures_io::AsyncWrite], [AsyncBufRead][futures_io::AsyncBufRead], and Iterator. See further documentation for the behaviors for each of these types at Interrupt.

Each of the trait implementations will behave normally with a small overhead to check shutdown state until shutdown has been initiated with Swansong::shut_down. When shutdown has been initiated, any type inside of an associated Interrupt will be interrupted/canceled/sealed at an appropriate time.

Swansong graceful shutdown is considered in progress while there are outstanding Guards. All guards must be dropped for shutdown to be considered complete. Guards can be created in three ways:

  • Swansong::guard returns a standalone Guard that can be moved into a closure or future, stored in a struct, or otherwise retained temporarily during a block of code that should not be abruptly stopped. For example, a http server might move a Guard into a closure or async task that handle an individual request.
  • Swansong::guarded returns a Guarded wrapper type provides transparent implementations of various traits like Future and Stream, as well as Derefing to the wrapped type. This is identical to moving a Guard into the wrapped type, but sometimes it’s easier to compose the guard around a named future than to move the guard into the future.
  • Interrupt::guarded allows an Interrupt wrapper to also act as a guard.

§Async Example

let swansong = Swansong::new();
executor::spawn(swansong.interrupt(pending::<()>()).guarded()).detach();
executor::spawn(swansong.guarded(Timer::after(Duration::from_secs(1)))).detach();
swansong.shut_down().await;

§Sync example

let swansong = Swansong::new();

thread::spawn({
   let guard = swansong.guard();
   move || {
       let _guard = guard;
       thread::sleep(Duration::from_secs(1));
    }
});

thread::spawn({
    let swansong = swansong.clone();
    move || {
        for n in swansong.interrupt(iter::repeat_with(|| fastrand::u8(..)))
        {
            thread::sleep(Duration::from_millis(100));
            println!("{n}");
        }
    }
});

thread::sleep(Duration::from_millis(500));

swansong.shut_down().block();

Structs§

  • The presence of a Guard delays shutdown.
  • Guarded is a convenient way to attach a Guard to another type.
  • A wrapper type that implements Stream when wrapping a [Stream] and [Future] when wrapping a Future
  • A Future that will be ready when the Swansong has been stopped AND all guards are dropped.
  • 🦢 Shutdown manager

Enums§

  • enum that represents the current status of this Swansong.