Replies: 1 comment
-
I've found a possible workaround, I copied graceful.rs to my own project and changed it like this: impl GracefulShutdown {
/// Create a new graceful shutdown helper.
pub fn new() -> Self {
let (tx, _) = watch::channel(());
Self { tx }
}
/// Wrap a future for graceful shutdown watching.
pub fn watch<C: GracefulConnection>(&self, conn: C) -> impl Future<Output = C::Output> {
let mut rx = self.tx.subscribe();
GracefulConnectionFuture::new(conn, async move {
let _ = rx.changed().await;
// hold onto the rx until the watched future is completed
rx
})
}
pub fn get_rx(&self) -> watch::Receiver<()> {
self.tx.subscribe()
}
pub fn from_rx<C: GracefulConnection>(
mut rx: watch::Receiver<()>,
conn: C,
) -> impl Future<Output = C::Output> {
GracefulConnectionFuture::new(conn, async move {
let _ = rx.changed().await;
// hold onto the rx until the watched future is completed
rx
})
}
/// Signal shutdown for all watched connections.
///
/// This returns a `Future` which will complete once all watched
/// connections have shutdown.
pub async fn shutdown(self) {
let Self { tx } = self;
// signal all the watched futures about the change
let _ = tx.send(());
// and then wait for all of them to complete
tx.closed().await;
}
} So this allows me to get an let listener = TcpListener::bind(addr2).await.unwrap();
let graceful = GracefulShutdown::new();
loop {
let tls_acceptor = tls_acceptor.clone();
tokio::select! {
Ok((tcp_stream, _addr)) = listener.accept() => {
let graceful_rx = graceful.get_rx();
tokio::task::spawn(async move {
let tls_stream = match tls_acceptor.accept(tcp_stream).into_fallible().await {
Ok(tls_stream) => tls_stream,
Err((err, mut io)) => {
eprintln!("failed to perform tls handshake: {err:?}");
let _ = io.write_all(PLAIN_TO_HTTPS_ERROR).await; // Ignore errors when sending the wrong protocl response
return;
}
};
let io = TokioIo::new(tls_stream);
let builder = auto::Builder::new(TokioExecutor::new());
let conn = builder.serve_connection(io, service_fn(index2));
let fut = GracefulShutdown::from_rx(graceful_rx, conn.into_owned());
if let Err(err) = fut.await
{
info!("Error serving connection: {:?}", err);
}
});
}
Ok(msg) = info_receiver.recv() => {
match msg {
WorkerMessage::Shutdown => {
info!("Stopping https_l");
break;
},
}
}
}
}
tokio::select! {
_ = graceful.shutdown() => {
info!("all connections gracefully closed");
},
_ = tokio::time::sleep(std::time::Duration::from_secs(10)) => {
error!("timed out wait for all connections to close");
}
} Maybe an idea to add an API like this? Or am I missing another way to do it? |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Hi, I'm trying to follow the examples for hyper-rustls and the guides and examples for hyper. Specifically I'm trying to combine this example from hyper-rustls and the graceful shutdown guide from hyper.
The problem I'm currently facing is that the rustls example accepts the TLS connection in a
tokio::task::spawn
, like this:So, I wanted to add a graceful watch to this connection, and I tried doing it like this:
(The info_receiver is connected to a sender which sends after ctrl+c)
The problem here is that the
graceful
value cannot be moved into the tokio::spawn call, because then it cannot be used on the next loop iteration. This is the diagnostic I get from rustc:This can be fixed by moving the
tokio::spawn
around the connection serving only, but I'm worried that this will cause the server to not accept new requests while a TLS connection is being handshaked. So this will limit the throughput of connection handling.Is there a good solution to this problem that I'm missing? I want to both support graceful stopping and HTTPS in my server!
Beta Was this translation helpful? Give feedback.
All reactions