@@ -17,7 +17,7 @@ use std::net::{IpAddr, SocketAddr};
1717use std:: str:: FromStr ;
1818use std:: time:: Duration ;
1919
20- use anyhow:: { Context , bail} ;
20+ use anyhow:: { Context , bail, ensure } ;
2121use bytesize:: ByteSize ;
2222use http:: HeaderMap ;
2323use quickwit_common:: fs:: get_disk_size;
@@ -31,6 +31,7 @@ use tracing::{info, warn};
3131use super :: { GrpcConfig , HealthConfig , RestConfig } ;
3232use crate :: config_value:: ConfigValue ;
3333use crate :: qw_env_vars:: * ;
34+ use crate :: serde_utils:: HumanDuration ;
3435use crate :: service:: QuickwitService ;
3536use crate :: storage_config:: StorageConfigs ;
3637use crate :: templating:: render_config;
@@ -457,6 +458,10 @@ struct RestConfigBuilder {
457458 pub extra_headers : HeaderMap ,
458459 #[ serde( default , rename = "tls" ) ]
459460 pub tls_config : Option < TlsConfig > ,
461+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
462+ pub max_connection_age : Option < HumanDuration > ,
463+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
464+ pub max_connection_age_grace : Option < HumanDuration > ,
460465}
461466
462467impl RestConfigBuilder {
@@ -475,11 +480,17 @@ impl RestConfigBuilder {
475480 if let Some ( tls_config) = & self . tls_config {
476481 tls_config. validate ( ) ?;
477482 }
483+ ensure ! (
484+ !( self . max_connection_age_grace. is_some( ) && self . max_connection_age. is_none( ) ) ,
485+ "`rest.max_connection_age_grace` requires `rest.max_connection_age` to be set"
486+ ) ;
478487 let rest_config = RestConfig {
479488 listen_addr : SocketAddr :: new ( listen_ip, listen_port) ,
480489 cors_allow_origins : self . cors_allow_origins ,
481490 extra_headers : self . extra_headers ,
482491 tls_config : self . tls_config ,
492+ max_connection_age : self . max_connection_age ,
493+ max_connection_age_grace : self . max_connection_age_grace ,
483494 } ;
484495 Ok ( rest_config)
485496 }
@@ -550,6 +561,8 @@ pub fn node_config_for_tests_from_ports(
550561 cors_allow_origins : Vec :: new ( ) ,
551562 extra_headers : HeaderMap :: new ( ) ,
552563 tls_config : None ,
564+ max_connection_age : None ,
565+ max_connection_age_grace : None ,
553566 } ;
554567 NodeConfig {
555568 cluster_id : default_cluster_id ( ) . unwrap ( ) ,
@@ -624,7 +637,46 @@ mod tests {
624637 config. rest_config. extra_headers. get( "x-header-2" ) . unwrap( ) ,
625638 "header-value-2"
626639 ) ;
640+ assert_eq ! (
641+ config. rest_config. tls_config,
642+ Some ( TlsConfig {
643+ cert_path: "/path/to/rest.crt" . to_string( ) ,
644+ key_path: "/path/to/rest.key" . to_string( ) ,
645+ ca_path: "/path/to/ca.crt" . to_string( ) ,
646+ expected_name: None ,
647+ verify_client_cert: true ,
648+ cert_reload_interval: HumanDuration :: try_from( "5m" . to_string( ) ) . unwrap( ) ,
649+ } )
650+ ) ;
651+ assert_eq ! (
652+ config. rest_config. max_connection_age,
653+ Some ( HumanDuration :: try_from( "30m" . to_string( ) ) . unwrap( ) )
654+ ) ;
655+ assert_eq ! (
656+ config. rest_config. max_connection_age_grace,
657+ Some ( HumanDuration :: try_from( "30s" . to_string( ) ) . unwrap( ) )
658+ ) ;
659+
627660 assert_eq ! ( config. grpc_config. max_message_size, ByteSize :: mb( 10 ) ) ;
661+ assert_eq ! (
662+ config. grpc_config. tls_config,
663+ Some ( TlsConfig {
664+ cert_path: "/path/to/grpc.crt" . to_string( ) ,
665+ key_path: "/path/to/grpc.key" . to_string( ) ,
666+ ca_path: "/path/to/ca.crt" . to_string( ) ,
667+ expected_name: Some ( "quickwit.local" . to_string( ) ) ,
668+ verify_client_cert: true ,
669+ cert_reload_interval: HumanDuration :: try_from( "5m" . to_string( ) ) . unwrap( ) ,
670+ } )
671+ ) ;
672+ assert_eq ! (
673+ config. grpc_config. max_connection_age,
674+ Some ( HumanDuration :: try_from( "1h" . to_string( ) ) . unwrap( ) )
675+ ) ;
676+ assert_eq ! (
677+ config. grpc_config. max_connection_age_grace,
678+ Some ( HumanDuration :: try_from( "10s" . to_string( ) ) . unwrap( ) )
679+ ) ;
628680
629681 assert_eq ! (
630682 config
0 commit comments