hyperium / hyper

An HTTP library for Rust
https://hyper.rs
MIT License
14.58k stars 1.6k forks source link

How to do Graceful Shutdown with low level API #2777

Closed jacob-pro closed 2 years ago

jacob-pro commented 2 years ago

I am currently using the low-level Http server API, which seems to suit my usage much better (https://github.com/hyperium/hyper/issues/2321)

But I am wondering how can I do a graceful shutdown, I currently have a run loop that looks like:

    loop {
        tokio::select! {
            conn = listener.accept() => {
                match conn.expect("Tls listener stream should be infinite") {
                    Ok(conn) => {
                        // Does a tokio::spawn with the http.serve_connection
                        handle_connection(http.clone(), conn, state.clone())
                    },
                    Err(e) => {
                        tracing::warn!("Bad connection: {}", e);
                    }
                }
            },
            message = rx.recv() => {
                match message {
                    Some(message) => {
                        match message {
                            Message::Shutdown => {
                                tracing::info!("Beginning shutdown");
                                break;
                            },
                            Message::ReplaceTlsAcceptor(acceptor, ack) => {
                                tracing::info!("Replacing tls acceptor");
                                listener.replace_acceptor(acceptor);
                                ack.send(()).ok();
                            },
                            Message::ReloadConfig(new_config, ack) => {
                                tracing::info!("Reloading config");
                                state = Arc::new(state.clone_with_new_config(new_config));
                                ack.send(()).ok();
                            }
                        }
                    },
                    None => {
                        tracing::warn!("Server channel is closed, shutting down");
                        break;
                    }
                }
            }
        }
    }
    // TODO: Figure out how to gracefully shutdown remaining connections

But what I would really like is some way of polling the remaining requests before exiting the server.

Something like that was proposed by @seanmonstar here: https://github.com/hyperium/hyper/issues/2321#issuecomment-734019314

jacob-pro commented 2 years ago

Ok so I've had a go at implementing this myself here, which seems to work:

https://github.com/jacob-pro/hyper-graceful

It is largely inspired on the tokio docs (using a broadcast to shutdown workers, and an mpsc to wait for them to complete):

https://tokio.rs/tokio/topics/shutdown

seanmonstar commented 2 years ago

Superceded by #2862