diff --git a/tonic/src/transport/channel/endpoint.rs b/tonic/src/transport/channel/endpoint.rs index 54c206ebe..f9c6e7631 100644 --- a/tonic/src/transport/channel/endpoint.rs +++ b/tonic/src/transport/channel/endpoint.rs @@ -30,6 +30,9 @@ pub struct Endpoint { pub(crate) init_connection_window_size: Option, pub(crate) tcp_keepalive: Option, pub(crate) tcp_nodelay: bool, + pub(crate) http2_keep_alive_interval: Option, + pub(crate) http2_keep_alive_timeout: Option, + pub(crate) http2_keep_alive_while_idle: Option, } impl Endpoint { @@ -167,6 +170,30 @@ impl Endpoint { } } + /// Set http2 KEEP_ALIVE_INTERVAL. Uses `hyper`'s default otherwise. + pub fn http2_keep_alive_interval(self, interval: Duration) -> Self { + Endpoint { + http2_keep_alive_interval: Some(interval), + ..self + } + } + + /// Set http2 KEEP_ALIVE_TIMEOUT. Uses `hyper`'s default otherwise. + pub fn keep_alive_timeout(self, duration: Duration) -> Self { + Endpoint { + http2_keep_alive_timeout: Some(duration), + ..self + } + } + + /// Set http2 KEEP_ALIVE_WHILE_IDLE. Uses `hyper`'s default otherwise. + pub fn keep_alive_while_idle(self, enabled: bool) -> Self { + Endpoint { + http2_keep_alive_while_idle: Some(enabled), + ..self + } + } + /// Create a channel from this config. pub async fn connect(&self) -> Result { let mut http = hyper::client::connect::HttpConnector::new(); @@ -215,6 +242,9 @@ impl From for Endpoint { init_connection_window_size: None, tcp_keepalive: None, tcp_nodelay: true, + http2_keep_alive_interval: None, + http2_keep_alive_timeout: None, + http2_keep_alive_while_idle: None, } } } diff --git a/tonic/src/transport/service/connection.rs b/tonic/src/transport/service/connection.rs index b90c1885d..dcb086f09 100644 --- a/tonic/src/transport/service/connection.rs +++ b/tonic/src/transport/service/connection.rs @@ -36,12 +36,23 @@ impl Connection { C::Future: Unpin + Send, C::Response: AsyncRead + AsyncWrite + HyperConnection + Unpin + Send + 'static, { - let settings = Builder::new() + let mut settings = Builder::new() .http2_initial_stream_window_size(endpoint.init_stream_window_size) .http2_initial_connection_window_size(endpoint.init_connection_window_size) .http2_only(true) + .http2_keep_alive_interval(endpoint.http2_keep_alive_interval) .clone(); + if let Some(val) = endpoint.http2_keep_alive_timeout { + settings.http2_keep_alive_timeout(val); + } + + if let Some(val) = endpoint.http2_keep_alive_while_idle { + settings.http2_keep_alive_while_idle(val); + } + + let settings = settings.clone(); + let stack = ServiceBuilder::new() .layer_fn(|s| AddOrigin::new(s, endpoint.uri.clone())) .optional_layer(endpoint.timeout.map(TimeoutLayer::new))