Skip to content

Cloning hyper_util::server::graceful::Watcher#272

Open
dtolnay wants to merge 1 commit intohyperium:masterfrom
dtolnay-contrib:graceful
Open

Cloning hyper_util::server::graceful::Watcher#272
dtolnay wants to merge 1 commit intohyperium:masterfrom
dtolnay-contrib:graceful

Conversation

@dtolnay
Copy link

@dtolnay dtolnay commented Feb 25, 2026

There was sensible opposition to cloning GracefulShutdown in #136 but I don't think it applies to Watcher.

I found the following pattern very complicated to make work without being able to clone a Watcher. My GracefulShutdown cannot be moved into the first spawn, and if it is not, then there is no way to obtain a separate Watcher for each execution of the second spawn.

let server = hyper_util::server::conn::auto::Builder::new(TokioExecutor::new());
let tls_acceptor: tokio_rustls::TlsAcceptor = ...;
let (listener_shutdown, mut listener_shutdown_rx) = tokio::sync::oneshot::channel();
let connections_shutdown = GracefulShutdown::new();
let graceful_watcher = connections_shutdown.watcher();

let listener_task = tokio::spawn(async move {
    loop {
        let Ok((tcp_stream, _remote_addr)) = (tokio::select! {
            incoming = tcp_listener.accept() => incoming,
            _ = &mut listener_shutdown_rx => break,
        }) else {
            continue;
        };

        let tls_acceptor = tls_acceptor.clone();
        let server = server.clone();
        LET GRACEFUL_WATCHER = GRACEFUL_WATCHER.CLONE();

        tokio::spawn(async move {
            let Ok(tls_stream) = tls_acceptor.accept(tcp_stream).await else {
                return;
            };
            let conn = server.serve_connection_with_upgrades(
                TokioIo::new(tls_stream),
                service_fn(move |req| ...),
            );
            let _ = graceful_watcher.watch(conn).await;
        });
    }
});

...

async fn stop() {
    listener_shutdown.send(()).unwrap();
    let handle = listener_task.abort_handle();
    if tokio::time::timeout(
        Duration::from_secs(2),
        future::join(listener_task, connections_shutdown.shutdown()),
    ) {
        handle.abort();
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant