Skip to main content

Swansong

Struct Swansong 

Source
pub struct Swansong { /* private fields */ }
Expand description

§🦢 Shutdown manager

See crate level docs for overview and example.

Two Swansongs are Eq if and only if they are clones of each other.

Implementations§

Source§

impl Swansong

Source

pub fn new() -> Swansong

Construct a new Swansong.

Source

pub fn with_guard_report() -> Swansong

Construct a new Swansong whose Guards record where and when they were created, for Swansong::guard_report. Its children do the same.

This is a debugging aid for shutdowns that stall on straggling guards, so it is chosen when the root is created: a report switched on later would miss the guards that already exist. Recording costs an allocation, a clock read and a lock on every guard; without it, creating and dropping a guard costs none of these.

let swansong = Swansong::with_guard_report();
let _guard = swansong.guard();
let report = swansong.guard_report();
assert_eq!(report.entries().len(), 1);
println!("{report}");
Source

pub fn shut_down(&self) -> ShutdownCompletion ⓘ

Initiate graceful shutdown.

This will gracefully stop any associated Interrupts.

This returns a ShutdownCompletion type, which can be blocked on with ShutdownCompletion::block or awaited as a Future.

Source

pub fn block_on_shutdown_completion(self)

Blocks the current thread until graceful shutdown is complete

Do not use this in async contexts. Instead, await the Swansong

Source

pub fn state(&self) -> ShutdownState

Determine if this Swansong is running, shutting down, or complete.

Source

pub fn shutting_down(&self) -> ShuttingDown ⓘ

Returns a ShuttingDown future that resolves when shutdown has been initiated on this Swansong.

This does not initiate shutdown — it only observes the transition from ShutdownState::Running to ShutdownState::ShuttingDown. The future resolves as soon as Swansong::shut_down is called (on this handle or any parent), or when the last root handle is dropped.

The returned future does not wait for outstanding Guards to drop. To wait for full shutdown (stopped and all guards dropped), use Swansong::shut_down or Swansong::into_future.

ShuttingDown can also be used in blocking contexts via ShuttingDown::block.

Source

pub fn interrupt<T>(&self, wrapped_type: T) -> Interrupt<T> ⓘ

Wrap any type with an Interrupt, allowing it to cancel or seal on shutdown.

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.

Source

pub fn guard(&self) -> Guard

Returns a new Guard, which forstalls shutdown until it is dropped.

The guard records the source location of this call for diagnostic purposes; see Swansong::guard_report.

Source

pub fn guard_count(&self) -> usize

The total number of outstanding Guards in this Swansong’s subtree.

For a root or leaf Swansong with no children, this is just the Guards created via this Swansong (and its clones). For a Swansong with children, it is the sum of Guards held in this node plus all Guards in all descendant subtrees. Child Swansong handles themselves are not counted as Guards; only real Guard instances are.

This walks the live subtree, reading each node’s shards and locking each shard’s child registry. Child registries retain reusable slots, so traversal time also depends on their historical peak occupancy, even after children have dropped. Prefer not to call this in a hot path.

Source

pub fn guard_report(&self) -> GuardReport

Report the provenance of the outstanding Guards in this Swansong’s subtree.

Under a root created with Swansong::with_guard_report, every guard records the source location it was created at (captured with #[track_caller], so it points at the swansong.guard(), swansong.guarded(..), or interrupt.guarded() call in your code; clones inherit the location of the guard they were cloned from) and when. This method aggregates the currently-live guards by creation site. It is useful for debugging a shutdown that is stalled on straggling guards — for example, by logging the report (via its Display implementation) when Swansong::shut_down has not completed within a deadline. Otherwise the report only has the guard_count.

Like Swansong::guard_count, this walks the live subtree and scans retained child-registry slots. When provenance is enabled, it also locks each shard’s guard registry to sweep dead entries and collect live records. Registry scans take place under their locks; this is intended for shutdown-time diagnostics rather than hot paths.

§Example
let swansong = Swansong::with_guard_report();
let guard = swansong.guard();
let report = swansong.guard_report();
assert_eq!(report.guard_count(), 1);
println!("{report}");
drop(guard);
assert!(swansong.guard_report().is_empty());
Source

pub fn child(&self) -> Swansong

Create a child Swansong linked to this parent.

The child can be independently shut down without affecting the parent. However, when the parent is shut down, the child will also be shut down. The parent’s shutdown will not be considered complete until the child Swansong and any associated ShutdownCompletions are dropped.

This supports multi-level hierarchies: a child can itself have children, forming a tree. Shutdown propagates downward through the entire tree.

§Performance

Creating a child registers it in amortized O(1) time, without scanning existing children. Registration takes a parent shard’s lock and increments the parent’s shared reference count. Roots spread registrations across shards, but different threads can select the same shard; child nodes have only one shard. The lock is also shared with interrupt registration and diagnostics, so cross-thread contention is still possible. Creating a child after the parent has stopped also stops the new child.

§Example: HTTP/3 server
let server = Swansong::new();

// Each connection gets its own child swansong
let connection = server.child();

// Connection can be shut down independently (e.g., on GOAWAY)
connection.shut_down();

// Or the entire server can shut down, which also stops all connections
// server.shut_down().await;
Source

pub fn guarded<T>(&self, wrapped_type: T) -> Guarded<T> ⓘ

Attach a guard to the provided type, delaying shutdown until it drops.

This function 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. See Guarded for more information about trait implementations on Guarded

Trait Implementations§

Source§

impl Clone for Swansong

Source§

fn clone(&self) -> Swansong

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) ¡ Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Swansong

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for Swansong

Source§

fn default() -> Swansong

Returns the “default value” for a type. Read more
Source§

impl Drop for Swansong

If we are dropping the last Swansong handle to a root node, stop the associated futures. Dropping the last handle to a child (non-root) node does not signal shutdown: the parent remains the governing authority, and the child stays in its current state until the parent propagates stop or until all Guards in the child’s subset naturally drain.

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl Eq for Swansong

Source§

impl IntoFuture for Swansong

Source§

type Output = ()

The output that the future will produce on completion.
Source§

type IntoFuture = ShutdownCompletion

Which kind of future are we turning this into?
Source§

fn into_future(self) -> <Swansong as IntoFuture>::IntoFuture

Creates a future from a value. Read more
Source§

impl PartialEq for Swansong

Source§

fn eq(&self, other: &Swansong) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) ¡ Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> CompatExt for T

Source§

fn compat(self) -> Compat<T> ⓘ
where T: Sized,

Applies the Compat adapter by value. Read more
Source§

fn compat_ref(&self) -> Compat<&T> ⓘ

Applies the Compat adapter by shared reference. Read more
Source§

fn compat_mut(&mut self) -> Compat<&mut T> ⓘ

Applies the Compat adapter by mutable reference. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.