MCPcopy Index your code
hub / github.com/Finomnis/tokio-graceful-shutdown

github.com/Finomnis/tokio-graceful-shutdown @0.19.3

Chat with this repo
repository ↗ · DeepWiki ↗ · release 0.19.3 ↗ · + Follow
272 symbols 829 edges 57 files 47 documented · 17%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

tokio-graceful-shutdown

Crates.io Crates.io License Build Status docs.rs Coverage Status

This crate provides utility functions to perform a graceful shutdown on tokio-rs based services.

Specifically, it provides:

  • Listening for shutdown requests from within subsystems
  • Manual shutdown initiation from within subsystems
  • Automatic shutdown on
    • SIGINT/SIGTERM/Ctrl+C
    • Subsystem failure
    • Subsystem panic
  • Clean shutdown procedure with timeout and error propagation
  • Subsystem nesting
  • Partial shutdown of a selected subsystem tree

Usage Example

async fn subsys1(subsys: &mut SubsystemHandle) -> Result<()>
{
    log::info!("Subsystem1 started.");
    subsys.on_shutdown_requested().await;
    log::info!("Subsystem1 stopped.");
    Ok(())
}

This shows a very basic asynchronous subsystem that simply starts, waits for the program shutdown to be triggered, and then stops itself.

This subsystem can now be executed like this:

#[tokio::main]
async fn main() -> Result<()> {
    Toplevel::new(async |s: &mut SubsystemHandle| {
        s.start(SubsystemBuilder::new("Subsys1", subsys1));
    })
    .catch_signals()
    .handle_shutdown_requests(Duration::from_millis(1000))
    .await
    .map_err(Into::into)
}

The Toplevel object is the root object of the subsystem tree. Subsystems can then be started in it using the start() method of its SubsystemHandle object.

The catch_signals() method signals the Toplevel object to listen for SIGINT/SIGTERM/Ctrl+C and initiate a shutdown thereafter.

handle_shutdown_requests() is the final and most important method of Toplevel. It idles until the program enters the shutdown mode. Then, it collects all the return values of the subsystems, determines the global error state and makes sure the shutdown completes within the given timeout. Lastly, it returns an error value that can be directly used as a return code for main().

Further examples can be seen in the examples folder.

Building

To use this library in your project, enter your project directory and run:

cargo add tokio-graceful-shutdown

To run one of the examples (here 01_normal_shutdown.rs), simply clone the tokio-graceful-shutdown repository, enter the repository folder and execute:

cargo run --example 01_normal_shutdown

Motivation

Performing a graceful shutdown on an asynchronous program is a non-trivial problem. There are several solutions, but they all have their drawbacks:

  • Global cancellation by forking with tokio::select. This is a wide-spread solution, but has the drawback that the cancelled tasks cannot react to it, so it's impossible for them to shut down gracefully.
  • Forking with tokio::spawn and signalling the desire to shutdown running tasks with mechanisms like tokio::CancellationToken. This allows tasks to shut down gracefully, but requires a lot of boilerplate code, like
  • Passing the tokens to the tasks
  • Waiting for the tasks to finish
  • Implementing a timeout mechanism to prevent hangs
  • Collecting subsystem return values
  • Making sure that subsystem errors get handled correctly

If then further functionality is required, as listening for signals like SIGINT or SIGTERM, the boilerplate code becomes quite messy.

And this is exactly what this crate aims to provide: clean abstractions to all this boilerplate code.

Contributions

Contributions are welcome!

I primarily wrote this crate for my own convenience, so any ideas for improvements are greatly appreciated.

Extension points exported contracts — how you extend this code

IntoSubsystem (Interface)
Allows a struct to be used as a subsystem. Using a struct that does not implement this trait as a subsystem is possible [3 …
src/into_subsystem.rs
ErrTypeTraits (Interface)
A collection of traits a custom error has to fulfill in order to be usable as the `ErrType` of [Toplevel]. [1 implementers]
src/lib.rs
FutureExt (Interface)
Extends the [std::future::Future] trait with useful utility functions. [1 implementers]
src/future_ext.rs
AsyncSubsysFn (Interface)
An async function that can be used as a subsystem. Note: External users should not implement this trait directly. Prefe [1 …
src/lib.rs

Core symbols most depended-on inside this repo

start
called by 124
src/subsystem/subsystem_handle.rs
handle_shutdown_requests
called by 55
src/toplevel.rs
on_shutdown_requested
called by 53
src/subsystem/subsystem_handle.rs
child_token
called by 27
src/utils/joiner_token.rs
clone
called by 26
src/runner/alive_guard.rs
catch_signals
called by 24
src/toplevel.rs
request_shutdown
called by 15
src/subsystem/subsystem_handle.rs
cancel_on_shutdown
called by 12
src/future_ext.rs

Shape

Function 154
Method 80
Class 28
Enum 6
Interface 4

Languages

Rust100%

Modules by API surface

tests/integration_test.rs29 symbols
src/subsystem/subsystem_handle.rs16 symbols
src/utils/joiner_token.rs14 symbols
src/errors.rs14 symbols
examples/18_error_type_passthrough.rs9 symbols
tests/abort.rs8 symbols
src/subsystem/nested_subsystem.rs8 symbols
tests/integration_test_2.rs7 symbols
src/utils/joiner_token/tests.rs7 symbols
src/runner/alive_guard.rs7 symbols
src/utils/remote_drop_collection.rs6 symbols
src/errors/tests.rs6 symbols

For agents

$ claude mcp add tokio-graceful-shutdown \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page