axum icon indicating copy to clipboard operation
axum copied to clipboard

More generally useful doc example for `.with_graceful shutdown()`

Open bittrance opened this issue 1 year ago • 2 comments

Motivation

The current doc example for .with_graceful_shutdown() does not quite show how shutdown/cancellation can be implemented. I think most readers will have a piece of code that looks like this and now wonders how to do shutdown.

let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
axum::serve(listener, app).await?;

In this scenario, the main issue is how to handle the fact that ::serve() blocks.

Solution

The easiest and most generally applicable way I can come up with to perform shutdown is to use tokio::sync::Notify to signal shutdown, like so:

let listener = tokio::net::TcpListener::bind("0.0.0.0:8082").await?;
let blocker = Arc::new(Notify::new());
let cancel = Arc::clone(&blocker);
tokio::spawn(
    axum::serve(listener, app)
        .with_graceful_shutdown(async move { blocker.notified().await })
        .into_future(),
);
// ...
cancel.notify_one();

I think this more generally useful pattern since the notify can be passed around and triggered where needed. In contrast, the select! strategy implied by the current doc is difficult to use in e.g. integration tests and where the api is a small component of a larger system.

bittrance avatar Jul 05 '24 10:07 bittrance

Ping @mladedav Follow-up questions to your comments.

bittrance avatar Sep 06 '24 07:09 bittrance

I'm not sure if this example is more "useful|.

I'm using https://lib.rs/crates/vss and it's quite clear how to use it

#[tokio::main]
async fn main() {
axum::serve(tcp, app)
    .with_graceful_shutdown(shutdown_signal())
    .await
    .unwrap();
}

async fn shutdown_signal() {
    vss::shutdown_signal().await;
    info!("signal received, starting graceful shutdown");
}

The current example has this simplicity, not having to introduce oneshot. So it's quite useful for beginners who quickly want something that works.

Your example is still useful if someone wants to send a signal to axum to shutdown. And I agree that your example enables testing. I really don't know how to choose here.

yanns avatar Oct 08 '24 17:10 yanns

thanks for your work @bittrance!

I think I agree with @yanns though. In the crates.io codebase we use something roughly similar to what the vss crate is doing and don't use channels for that either. It might be worth having an example that uses a channel instead too, but I don't think we should replace the existing examples.

IMHO we should close this PR and then we can discuss a new example proposal in a new PR :)

Turbo87 avatar Dec 26 '24 10:12 Turbo87