@@ -47,6 +47,7 @@ pub struct PoolConfig {
4747 pub connection_config : ConnectionConfig ,
4848 pub pool_size : PoolSize ,
4949 pub can_use_shard_aware_port : bool ,
50+ pub keepalive_interval : Option < Duration > ,
5051}
5152
5253impl Default for PoolConfig {
@@ -55,6 +56,7 @@ impl Default for PoolConfig {
5556 connection_config : Default :: default ( ) ,
5657 pool_size : Default :: default ( ) ,
5758 can_use_shard_aware_port : true ,
59+ keepalive_interval : None ,
5860 }
5961 }
6062}
@@ -137,6 +139,7 @@ pub struct NodeConnectionPool {
137139 conns : Arc < ArcSwap < MaybePoolConnections > > ,
138140 use_keyspace_request_sender : mpsc:: Sender < UseKeyspaceRequest > ,
139141 _refiller_handle : RemoteHandle < ( ) > ,
142+ _keepaliver_handle : Option < RemoteHandle < ( ) > > ,
140143 pool_updated_notify : Arc < Notify > ,
141144}
142145
@@ -150,6 +153,8 @@ impl NodeConnectionPool {
150153 let ( use_keyspace_request_sender, use_keyspace_request_receiver) = mpsc:: channel ( 1 ) ;
151154 let pool_updated_notify = Arc :: new ( Notify :: new ( ) ) ;
152155
156+ let keepalive_interval = pool_config. keepalive_interval ;
157+
153158 let refiller = PoolRefiller :: new (
154159 address,
155160 port,
@@ -159,13 +164,29 @@ impl NodeConnectionPool {
159164 ) ;
160165
161166 let conns = refiller. get_shared_connections ( ) ;
162- let ( fut, handle ) = refiller. run ( use_keyspace_request_receiver) . remote_handle ( ) ;
167+ let ( fut, refiller_handle ) = refiller. run ( use_keyspace_request_receiver) . remote_handle ( ) ;
163168 tokio:: spawn ( fut) ;
164169
170+ let keepaliver_handle = if let Some ( interval) = keepalive_interval {
171+ let keepaliver = Keepaliver {
172+ connections : conns. clone ( ) ,
173+ keepalive_interval : interval,
174+ node_address : address,
175+ } ;
176+
177+ let ( fut, keepaliver_handle) = keepaliver. work ( ) . remote_handle ( ) ;
178+ tokio:: spawn ( fut) ;
179+
180+ Some ( keepaliver_handle)
181+ } else {
182+ None
183+ } ;
184+
165185 Self {
166186 conns,
167187 use_keyspace_request_sender,
168- _refiller_handle : handle,
188+ _refiller_handle : refiller_handle,
189+ _keepaliver_handle : keepaliver_handle,
169190 pool_updated_notify,
170191 }
171192 }
@@ -315,6 +336,82 @@ impl NodeConnectionPool {
315336 }
316337}
317338
339+ struct Keepaliver {
340+ connections : Arc < ArcSwap < MaybePoolConnections > > ,
341+ node_address : IpAddr , // This address is only used to enrich the log messages
342+ keepalive_interval : Duration ,
343+ }
344+
345+ impl Keepaliver {
346+ pub fn load_connections ( & self ) -> Vec < Arc < Connection > > {
347+ use MaybePoolConnections :: * ;
348+ use PoolConnections :: * ;
349+
350+ let pool = self . connections . load_full ( ) ;
351+ match & * pool {
352+ Ready ( NotSharded ( conns) ) => conns. clone ( ) ,
353+ Ready ( Sharded { connections, .. } ) => connections. iter ( ) . flatten ( ) . cloned ( ) . collect ( ) ,
354+ Initializing => vec ! [ ] ,
355+ Broken => {
356+ debug ! ( "Cannot send connection keepalives for node {} as there are no alive connections in the pool" , self . node_address) ;
357+ vec ! [ ]
358+ }
359+ }
360+ }
361+
362+ async fn work ( self ) {
363+ let mut interval = tokio:: time:: interval ( self . keepalive_interval ) ;
364+ interval. tick ( ) . await ; // Use up the first, instant tick.
365+
366+ // Default behaviour (Burst) is not suitable for sending keepalives.
367+ interval. set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Delay ) ;
368+
369+ // Wait for the second tick (so that `self.keepalive_interval` time passes since entering
370+ // this function)
371+ interval. tick ( ) . await ;
372+
373+ loop {
374+ let send_keepalives = self . send_keepalives ( ) ;
375+
376+ tokio:: select! {
377+ _ = send_keepalives => {
378+ // Sending keepalives finished before receiving new tick.
379+ // Wait for the new tick and start over.
380+ interval. tick( ) . await ;
381+ }
382+ _ = interval. tick( ) => {
383+ // New tick arrived before `send_keepalives` was finished.
384+ // Stop polling `send_keepalives` and start over.
385+ //
386+ // `Interval::tick()` is cancellation safe, so it's ok to use it like that.
387+ }
388+ }
389+ }
390+ }
391+
392+ async fn send_keepalives ( & self ) {
393+ let connections = self . load_connections ( ) ;
394+ let mut futures = connections
395+ . into_iter ( )
396+ . map ( Self :: send_keepalive_query)
397+ . collect :: < FuturesUnordered < _ > > ( ) ;
398+
399+ while futures. next ( ) . await . is_some ( ) { }
400+ }
401+
402+ async fn send_keepalive_query ( connection : Arc < Connection > ) {
403+ if let Err ( err) = connection
404+ . query_single_page ( "select key from system.local where key = 'local'" , & [ ] )
405+ . await
406+ {
407+ warn ! (
408+ "Failed to execute keepalive request on a connection {:p} - {}" ,
409+ connection, err
410+ ) ;
411+ }
412+ }
413+ }
414+
318415const EXCESS_CONNECTION_BOUND_PER_SHARD_MULTIPLIER : usize = 10 ;
319416
320417// TODO: Make it configurable through a policy (issue #184)
0 commit comments