Skip to content

Commit d469de5

Browse files
committed
Improve graceful shutdown with draining
In-progress connections now prevent the server from returning until they are complete, ensuing that graceful termination can still happen.
1 parent 8c69cff commit d469de5

File tree

1 file changed

+43
-20
lines changed
  • tonic/src/transport/server

1 file changed

+43
-20
lines changed

tonic/src/transport/server/mod.rs

+43-20
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use tokio_stream::StreamExt as _;
2525
use tower::util::BoxCloneService;
2626
use tower::util::Oneshot;
2727
use tower::ServiceExt;
28+
use tracing::debug;
2829
use tracing::trace;
2930

3031
#[cfg(feature = "tls")]
@@ -563,14 +564,14 @@ impl<L> Server<L> {
563564

564565
tokio::pin!(incoming);
565566

567+
let graceful = signal.is_some();
566568
let sig = Fuse { inner: signal };
567569
tokio::pin!(sig);
568570

569571
loop {
570572
tokio::select! {
571573
_ = &mut sig => {
572574
trace!("signal received, shutting down");
573-
drop(signal_rx);
574575
break;
575576
},
576577
io = incoming.next() => {
@@ -580,7 +581,9 @@ impl<L> Server<L> {
580581
trace!("error accepting connection: {:#}", e);
581582
continue;
582583
},
583-
None => break,
584+
None => {
585+
break
586+
},
584587
};
585588

586589
trace!("connection accepted");
@@ -595,11 +598,23 @@ impl<L> Server<L> {
595598
.map_err(super::Error::from_source)?;
596599
let hyper_svc = TowerToHyperService::new(req_svc);
597600

598-
serve_connection(io, hyper_svc, builder.clone(), signal_tx.clone());
601+
serve_connection(io, hyper_svc, builder.clone(), graceful.then(|| signal_rx.clone()));
599602
}
600603
}
601604
}
602605

606+
if graceful {
607+
let _ = signal_tx.send(());
608+
drop(signal_rx);
609+
trace!(
610+
"waiting for {} connections to close",
611+
signal_tx.receiver_count()
612+
);
613+
614+
// Wait for all connections to close
615+
signal_tx.closed().await;
616+
}
617+
603618
Ok(())
604619
}
605620
}
@@ -610,7 +625,7 @@ fn serve_connection<IO, S>(
610625
io: ServerIo<IO>,
611626
hyper_svc: TowerToHyperService<S>,
612627
builder: hyper_util::server::conn::auto::Builder<TokioExecutor>,
613-
watcher: Arc<tokio::sync::watch::Sender<()>>,
628+
mut watcher: Option<tokio::sync::watch::Receiver<()>>,
614629
) where
615630
S: Service<Request, Response = Response> + Clone + Send + 'static,
616631
S::Future: Send + 'static,
@@ -619,30 +634,32 @@ fn serve_connection<IO, S>(
619634
IO::ConnectInfo: Clone + Send + Sync + 'static,
620635
{
621636
tokio::spawn(async move {
622-
let sig = Fuse {
623-
inner: Some(watcher.closed()),
624-
};
637+
{
638+
let sig = Fuse {
639+
inner: watcher.as_mut().map(|w| w.changed()),
640+
};
625641

626-
tokio::pin!(sig);
642+
tokio::pin!(sig);
627643

628-
let conn = builder.serve_connection(TokioIo::new(io), hyper_svc);
629-
tokio::pin!(conn);
644+
let conn = builder.serve_connection(TokioIo::new(io), hyper_svc);
645+
tokio::pin!(conn);
630646

631-
loop {
632-
tokio::select! {
633-
rv = &mut conn => {
634-
if let Err(err) = rv {
635-
trace!("failed serving connection: {:#}", err);
647+
loop {
648+
tokio::select! {
649+
rv = &mut conn => {
650+
if let Err(err) = rv {
651+
debug!("failed serving connection: {:#}", err);
652+
}
653+
break;
654+
},
655+
_ = &mut sig => {
656+
conn.as_mut().graceful_shutdown();
636657
}
637-
break;
638-
},
639-
_ = &mut sig => {
640-
trace!("signal received, shutting down");
641-
conn.as_mut().graceful_shutdown();
642658
}
643659
}
644660
}
645661

662+
drop(watcher);
646663
trace!("connection closed");
647664
});
648665
}
@@ -1057,6 +1074,12 @@ struct Fuse<F> {
10571074
inner: Option<F>,
10581075
}
10591076

1077+
impl<F> Fuse<F> {
1078+
fn is_terminated(self: &Pin<&mut Self>) -> bool {
1079+
self.inner.is_none()
1080+
}
1081+
}
1082+
10601083
impl<F> Future for Fuse<F>
10611084
where
10621085
F: Future,

0 commit comments

Comments
 (0)