feat(transport): Expose tcp keepalive to clients & servers (#151)

This commit is contained in:
Philippe GASSMANN
2019-12-06 11:56:06 -05:00
committed by Lucio Franco
parent 3387ef900f
commit caccfad7e7
4 changed files with 47 additions and 9 deletions
+17
View File
@@ -29,6 +29,7 @@ pub struct Endpoint {
Option<Arc<dyn Fn(&mut http::HeaderMap) + Send + Sync + 'static>>, Option<Arc<dyn Fn(&mut http::HeaderMap) + Send + Sync + 'static>>,
pub(super) init_stream_window_size: Option<u32>, pub(super) init_stream_window_size: Option<u32>,
pub(super) init_connection_window_size: Option<u32>, pub(super) init_connection_window_size: Option<u32>,
pub(super) tcp_keepalive: Option<Duration>,
} }
impl Endpoint { impl Endpoint {
@@ -83,6 +84,21 @@ impl Endpoint {
} }
} }
/// Set whether TCP keepalive messages are enabled on accepted connections.
///
/// If `None` is specified, keepalive is disabled, otherwise the duration
/// specified will be the time to remain idle before sending TCP keepalive
/// probes.
///
/// Default is no keepalive (`None`)
///
pub fn tcp_keepalive(self, tcp_keepalive: Option<Duration>) -> Self {
Endpoint {
tcp_keepalive,
..self
}
}
/// Apply a concurrency limit to each request. /// Apply a concurrency limit to each request.
/// ///
/// ``` /// ```
@@ -174,6 +190,7 @@ impl From<Uri> for Endpoint {
interceptor_headers: None, interceptor_headers: None,
init_stream_window_size: None, init_stream_window_size: None,
init_connection_window_size: None, init_connection_window_size: None,
tcp_keepalive: None,
} }
} }
} }
+21 -2
View File
@@ -14,6 +14,7 @@ use hyper::{
server::{accept::Accept, conn}, server::{accept::Accept, conn},
Body, Body,
}; };
use std::time::Duration;
use std::{ use std::{
fmt, fmt,
future::Future, future::Future,
@@ -54,6 +55,7 @@ pub struct Server {
init_stream_window_size: Option<u32>, init_stream_window_size: Option<u32>,
init_connection_window_size: Option<u32>, init_connection_window_size: Option<u32>,
max_concurrent_streams: Option<u32>, max_concurrent_streams: Option<u32>,
tcp_keepalive: Option<Duration>,
} }
/// A stack based `Service` router. /// A stack based `Service` router.
@@ -147,6 +149,21 @@ impl Server {
} }
} }
/// Set whether TCP keepalive messages are enabled on accepted connections.
///
/// If `None` is specified, keepalive is disabled, otherwise the duration
/// specified will be the time to remain idle before sending TCP keepalive
/// probes.
///
/// Default is no keepalive (`None`)
///
pub fn tcp_keepalive(self, tcp_keepalive: Option<Duration>) -> Self {
Server {
tcp_keepalive,
..self
}
}
/// Intercept the execution of gRPC methods. /// Intercept the execution of gRPC methods.
/// ///
/// ``` /// ```
@@ -204,11 +221,12 @@ impl Server {
let init_connection_window_size = self.init_connection_window_size; let init_connection_window_size = self.init_connection_window_size;
let init_stream_window_size = self.init_stream_window_size; let init_stream_window_size = self.init_stream_window_size;
let max_concurrent_streams = self.max_concurrent_streams; let max_concurrent_streams = self.max_concurrent_streams;
let tcp_keepalive = self.tcp_keepalive;
// let timeout = self.timeout.clone(); // let timeout = self.timeout.clone();
let incoming = hyper::server::accept::from_stream::<_, _, crate::Error>( let incoming = hyper::server::accept::from_stream::<_, _, crate::Error>(
async_stream::try_stream! { async_stream::try_stream! {
let mut tcp = TcpIncoming::bind(addr)?; let mut tcp = TcpIncoming::bind(addr, tcp_keepalive)?;
while let Some(stream) = tcp.try_next().await? { while let Some(stream) = tcp.try_next().await? {
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
@@ -400,9 +418,10 @@ struct TcpIncoming {
} }
impl TcpIncoming { impl TcpIncoming {
fn bind(addr: SocketAddr) -> Result<Self, crate::Error> { fn bind(addr: SocketAddr, tcp_keepalive: Option<Duration>) -> Result<Self, crate::Error> {
let mut inner = conn::AddrIncoming::bind(&addr).map_err(Box::new)?; let mut inner = conn::AddrIncoming::bind(&addr).map_err(Box::new)?;
inner.set_nodelay(true); inner.set_nodelay(true);
inner.set_keepalive(tcp_keepalive);
Ok(Self { inner }) Ok(Self { inner })
} }
+2 -2
View File
@@ -28,10 +28,10 @@ pub(crate) struct Connection {
impl Connection { impl Connection {
pub(crate) async fn new(endpoint: Endpoint) -> Result<Self, crate::Error> { pub(crate) async fn new(endpoint: Endpoint) -> Result<Self, crate::Error> {
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
let connector = connector(endpoint.tls.clone()); let connector = connector(endpoint.tls.clone(), endpoint.tcp_keepalive);
#[cfg(not(feature = "tls"))] #[cfg(not(feature = "tls"))]
let connector = connector(); let connector = connector(endpoint.tcp_keepalive);
let settings = Builder::new() let settings = Builder::new()
.http2_initial_stream_window_size(endpoint.init_stream_window_size) .http2_initial_stream_window_size(endpoint.init_stream_window_size)
+7 -5
View File
@@ -6,20 +6,22 @@ use hyper::client::connect::HttpConnector;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::time::Duration;
use tower_make::MakeConnection; use tower_make::MakeConnection;
use tower_service::Service; use tower_service::Service;
#[cfg(not(feature = "tls"))] #[cfg(not(feature = "tls"))]
pub(crate) fn connector() -> HttpConnector { pub(crate) fn connector(tcp_keepalive: Option<Duration>) -> HttpConnector {
let mut http = HttpConnector::new(); let mut http = HttpConnector::new();
http.enforce_http(false); http.enforce_http(false);
http.set_nodelay(true); http.set_nodelay(true);
http.set_keepalive(tcp_keepalive);
http http
} }
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
pub(crate) fn connector(tls: Option<TlsConnector>) -> Connector { pub(crate) fn connector(tls: Option<TlsConnector>, tcp_keepalive: Option<Duration>) -> Connector {
Connector::new(tls) Connector::new(tls, tcp_keepalive)
} }
pub(crate) struct Connector { pub(crate) struct Connector {
@@ -30,11 +32,11 @@ pub(crate) struct Connector {
impl Connector { impl Connector {
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
pub(crate) fn new(tls: Option<TlsConnector>) -> Self { pub(crate) fn new(tls: Option<TlsConnector>, tcp_keepalive: Option<Duration>) -> Self {
let mut http = HttpConnector::new(); let mut http = HttpConnector::new();
http.enforce_http(false); http.enforce_http(false);
http.set_nodelay(true); http.set_nodelay(true);
http.set_keepalive(tcp_keepalive);
Self { http, tls } Self { http, tls }
} }
} }