Skip to content

Commit c0b947f

Browse files
nuel77jsdw
andauthored
feat(keepalive): expose tcp keep-alive options (#1583)
* expose tcp keep-alive options * expose tcp keep-alive options * add to client * add to server * cleanup * serve only if http2 is available * http2 is always available from crates feature flags * remove http2 feature flag * typo fix --------- Co-authored-by: James Wilson <james@jsdw.me>
1 parent fa7d1c8 commit c0b947f

File tree

3 files changed

+108
-2
lines changed

3 files changed

+108
-2
lines changed

client/http-client/src/client.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ pub struct HttpClientBuilder<HttpMiddleware = Identity, RpcMiddleware = Logger>
9090
rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
9191
tcp_no_delay: bool,
9292
max_concurrent_requests: Option<usize>,
93+
keep_alive_duration: Option<Duration>,
94+
keep_alive_interval: Option<Duration>,
95+
keep_alive_retries: Option<u32>,
9396
}
9497

9598
impl<HttpMiddleware, RpcMiddleware> HttpClientBuilder<HttpMiddleware, RpcMiddleware> {
@@ -210,6 +213,24 @@ impl<HttpMiddleware, RpcMiddleware> HttpClientBuilder<HttpMiddleware, RpcMiddlew
210213
self
211214
}
212215

216+
/// Set the keep-alive duration.
217+
pub fn set_keep_alive(mut self, duration: Option<Duration>) -> Self {
218+
self.keep_alive_duration = duration;
219+
self
220+
}
221+
222+
/// Set the keep-alive interval.
223+
pub fn set_keep_alive_interval(mut self, interval: Option<Duration>) -> Self {
224+
self.keep_alive_interval = interval;
225+
self
226+
}
227+
228+
/// Set the number of keep-alive retries.
229+
pub fn set_keep_alive_retries(mut self, retries: Option<u32>) -> Self {
230+
self.keep_alive_retries = retries;
231+
self
232+
}
233+
213234
/// Set the RPC middleware.
214235
pub fn set_rpc_middleware<T>(self, rpc_builder: RpcServiceBuilder<T>) -> HttpClientBuilder<HttpMiddleware, T> {
215236
HttpClientBuilder {
@@ -224,6 +245,9 @@ impl<HttpMiddleware, RpcMiddleware> HttpClientBuilder<HttpMiddleware, RpcMiddlew
224245
request_timeout: self.request_timeout,
225246
tcp_no_delay: self.tcp_no_delay,
226247
max_concurrent_requests: self.max_concurrent_requests,
248+
keep_alive_duration: self.keep_alive_duration,
249+
keep_alive_interval: self.keep_alive_interval,
250+
keep_alive_retries: self.keep_alive_retries,
227251
}
228252
}
229253

@@ -244,6 +268,9 @@ impl<HttpMiddleware, RpcMiddleware> HttpClientBuilder<HttpMiddleware, RpcMiddlew
244268
request_timeout: self.request_timeout,
245269
tcp_no_delay: self.tcp_no_delay,
246270
max_concurrent_requests: self.max_concurrent_requests,
271+
keep_alive_duration: self.keep_alive_duration,
272+
keep_alive_retries: self.keep_alive_retries,
273+
keep_alive_interval: self.keep_alive_interval,
247274
}
248275
}
249276
}
@@ -271,6 +298,9 @@ where
271298
service_builder,
272299
tcp_no_delay,
273300
rpc_middleware,
301+
keep_alive_duration,
302+
keep_alive_interval,
303+
keep_alive_retries,
274304
..
275305
} = self;
276306

@@ -280,6 +310,9 @@ where
280310
headers,
281311
tcp_no_delay,
282312
service_builder,
313+
keep_alive_duration,
314+
keep_alive_interval,
315+
keep_alive_retries,
283316
#[cfg(feature = "tls")]
284317
certificate_store,
285318
}
@@ -313,6 +346,9 @@ impl Default for HttpClientBuilder {
313346
rpc_middleware: RpcServiceBuilder::default().rpc_logger(1024),
314347
tcp_no_delay: true,
315348
max_concurrent_requests: None,
349+
keep_alive_duration: None,
350+
keep_alive_interval: None,
351+
keep_alive_retries: None,
316352
}
317353
}
318354
}

client/http-client/src/transport.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ pub struct HttpTransportClientBuilder<L> {
9898
pub(crate) service_builder: tower::ServiceBuilder<L>,
9999
/// TCP_NODELAY
100100
pub(crate) tcp_no_delay: bool,
101+
/// KEEP_ALIVE duration
102+
pub(crate) keep_alive_duration: Option<std::time::Duration>,
103+
/// KEEP_ALIVE interval
104+
pub(crate) keep_alive_interval: Option<std::time::Duration>,
105+
/// KEEP_ALIVE retries
106+
pub(crate) keep_alive_retries: Option<u32>,
101107
}
102108

103109
impl Default for HttpTransportClientBuilder<Identity> {
@@ -117,6 +123,9 @@ impl HttpTransportClientBuilder<Identity> {
117123
headers: HeaderMap::new(),
118124
service_builder: tower::ServiceBuilder::new(),
119125
tcp_no_delay: true,
126+
keep_alive_duration: None,
127+
keep_alive_interval: None,
128+
keep_alive_retries: None,
120129
}
121130
}
122131
}
@@ -157,6 +166,24 @@ impl<L> HttpTransportClientBuilder<L> {
157166
self
158167
}
159168

169+
/// Configure the keep-alive duration for the connection.
170+
pub fn set_keep_alive(mut self, duration: Option<std::time::Duration>) -> Self {
171+
self.keep_alive_duration = duration;
172+
self
173+
}
174+
175+
/// Configure the keep-alive interval for the connection.
176+
pub fn set_keep_alive_interval(mut self, interval: Option<std::time::Duration>) -> Self {
177+
self.keep_alive_interval = interval;
178+
self
179+
}
180+
181+
/// Configure the number of keep-alive retries for the connection.
182+
pub fn set_keep_alive_retries(mut self, retries: Option<u32>) -> Self {
183+
self.keep_alive_retries = retries;
184+
self
185+
}
186+
160187
/// Configure a tower service.
161188
pub fn set_service<T>(self, service: tower::ServiceBuilder<T>) -> HttpTransportClientBuilder<T> {
162189
HttpTransportClientBuilder {
@@ -167,6 +194,9 @@ impl<L> HttpTransportClientBuilder<L> {
167194
max_response_size: self.max_response_size,
168195
service_builder: service,
169196
tcp_no_delay: self.tcp_no_delay,
197+
keep_alive_duration: self.keep_alive_duration,
198+
keep_alive_retries: self.keep_alive_retries,
199+
keep_alive_interval: self.keep_alive_interval,
170200
}
171201
}
172202

@@ -187,6 +217,9 @@ impl<L> HttpTransportClientBuilder<L> {
187217
headers,
188218
service_builder,
189219
tcp_no_delay,
220+
keep_alive_duration,
221+
keep_alive_interval,
222+
keep_alive_retries,
190223
} = self;
191224
let mut url = Url::parse(target.as_ref()).map_err(|e| Error::Url(format!("Invalid URL: {e}")))?;
192225

@@ -199,6 +232,9 @@ impl<L> HttpTransportClientBuilder<L> {
199232
"http" => {
200233
let mut connector = HttpConnector::new();
201234
connector.set_nodelay(tcp_no_delay);
235+
connector.set_keepalive(keep_alive_duration);
236+
connector.set_keepalive_interval(keep_alive_interval);
237+
connector.set_keepalive_retries(keep_alive_retries);
202238
HttpBackend::Http(Client::builder(TokioExecutor::new()).build(connector))
203239
}
204240
#[cfg(feature = "tls")]
@@ -212,6 +248,9 @@ impl<L> HttpTransportClientBuilder<L> {
212248
let mut http_conn = HttpConnector::new();
213249
http_conn.set_nodelay(tcp_no_delay);
214250
http_conn.enforce_http(false);
251+
http_conn.set_keepalive(keep_alive_duration);
252+
http_conn.set_keepalive_interval(keep_alive_interval);
253+
http_conn.set_keepalive_retries(keep_alive_retries);
215254

216255
let https_conn = match certificate_store {
217256
CertificateStore::Native => {

server/src/server.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ pub struct ServerConfig {
196196
pub(crate) id_provider: Arc<dyn IdProvider>,
197197
/// `TCP_NODELAY` settings.
198198
pub(crate) tcp_no_delay: bool,
199+
/// `KEEP_ALIVE` duration.
200+
pub(crate) keep_alive: Option<std::time::Duration>,
201+
/// `KEEP_ALIVE_TIMEOUT` duration.
202+
pub(crate) keep_alive_timeout: Duration,
199203
}
200204

201205
/// The builder to configure and create a JSON-RPC server configuration.
@@ -225,6 +229,10 @@ pub struct ServerConfigBuilder {
225229
id_provider: Arc<dyn IdProvider>,
226230
/// `TCP_NODELAY` settings.
227231
tcp_no_delay: bool,
232+
/// `KEEP_ALIVE` duration.
233+
keep_alive: Option<std::time::Duration>,
234+
/// `KEEP_ALIVE_TIMEOUT` duration.
235+
keep_alive_timeout: std::time::Duration,
228236
}
229237

230238
/// Builder for [`TowerService`].
@@ -363,6 +371,9 @@ impl Default for ServerConfigBuilder {
363371
ping_config: None,
364372
id_provider: Arc::new(RandomIntegerIdProvider),
365373
tcp_no_delay: true,
374+
keep_alive: None,
375+
//same as `hyper` default
376+
keep_alive_timeout: Duration::from_secs(20),
366377
}
367378
}
368379
}
@@ -518,6 +529,18 @@ impl ServerConfigBuilder {
518529
self
519530
}
520531

532+
/// Configure `KEEP_ALIVE` hyper to the supplied value `keep_alive`.
533+
pub fn set_keep_alive(mut self, keep_alive: Option<std::time::Duration>) -> Self {
534+
self.keep_alive = keep_alive;
535+
self
536+
}
537+
538+
/// Configure `KEEP_ALIVE_TIMEOUT` hyper to the supplied value `keep_alive_timeout`.
539+
pub fn set_keep_alive_timeout(mut self, keep_alive_timeout: Duration) -> Self {
540+
self.keep_alive_timeout = keep_alive_timeout;
541+
self
542+
}
543+
521544
/// Build the [`ServerConfig`].
522545
pub fn build(self) -> ServerConfig {
523546
ServerConfig {
@@ -533,6 +556,8 @@ impl ServerConfigBuilder {
533556
ping_config: self.ping_config,
534557
id_provider: self.id_provider,
535558
tcp_no_delay: self.tcp_no_delay,
559+
keep_alive: self.keep_alive,
560+
keep_alive_timeout: self.keep_alive_timeout,
536561
}
537562
}
538563
}
@@ -1166,6 +1191,9 @@ where
11661191
return;
11671192
}
11681193

1194+
let keep_alive = server_cfg.keep_alive;
1195+
let keep_alive_timeout = server_cfg.keep_alive_timeout;
1196+
11691197
let tower_service = TowerServiceNoHttp {
11701198
inner: ServiceData {
11711199
server_cfg,
@@ -1180,11 +1208,14 @@ where
11801208

11811209
let service = http_middleware.service(tower_service);
11821210

1183-
tokio::spawn(async {
1211+
tokio::spawn(async move {
11841212
// this requires Clone.
11851213
let service = crate::utils::TowerToHyperService::new(service);
11861214
let io = TokioIo::new(socket);
1187-
let builder = hyper_util::server::conn::auto::Builder::new(TokioExecutor::new());
1215+
let mut builder = hyper_util::server::conn::auto::Builder::new(TokioExecutor::new());
1216+
1217+
//default is true for http1, if set to false then websocket connections will not be upgraded.
1218+
builder.http2().keep_alive_interval(keep_alive).keep_alive_timeout(keep_alive_timeout);
11881219

11891220
let conn = builder.serve_connection_with_upgrades(io, service);
11901221
let stopped = stop_handle.shutdown();

0 commit comments

Comments
 (0)