@@ -16,6 +16,7 @@ pub use native_tls_opts::ClientIdentity;
16
16
pub use rustls_opts:: ClientIdentity ;
17
17
18
18
use percent_encoding:: percent_decode;
19
+ use rand:: Rng ;
19
20
use url:: { Host , Url } ;
20
21
21
22
use std:: {
@@ -26,7 +27,7 @@ use std::{
26
27
path:: Path ,
27
28
str:: FromStr ,
28
29
sync:: Arc ,
29
- time:: Duration ,
30
+ time:: { Duration , Instant } ,
30
31
vec,
31
32
} ;
32
33
@@ -209,6 +210,8 @@ pub struct PoolOpts {
209
210
constraints : PoolConstraints ,
210
211
inactive_connection_ttl : Duration ,
211
212
ttl_check_interval : Duration ,
213
+ abs_conn_ttl : Option < Duration > ,
214
+ abs_conn_ttl_jitter : Option < Duration > ,
212
215
reset_connection : bool ,
213
216
}
214
217
@@ -273,6 +276,49 @@ impl PoolOpts {
273
276
self . reset_connection
274
277
}
275
278
279
+ /// Sets an absolute TTL after which a connection is removed from the pool.
280
+ /// This may push the pool below the requested minimum pool size and is indepedent of the
281
+ /// idle TTL.
282
+ /// The absolute TTL is disabled by default.
283
+ /// Fractions of seconds are ignored.
284
+ pub fn with_abs_conn_ttl ( mut self , ttl : Option < Duration > ) -> Self {
285
+ self . abs_conn_ttl = ttl;
286
+ self
287
+ }
288
+
289
+ /// Optionally, the absolute TTL can be extended by a per-connection random amount
290
+ /// bounded by `jitter`.
291
+ /// Setting `abs_conn_ttl_jitter` without `abs_conn_ttl` has no effect.
292
+ /// Fractions of seconds are ignored.
293
+ pub fn with_abs_conn_ttl_jitter ( mut self , jitter : Option < Duration > ) -> Self {
294
+ self . abs_conn_ttl_jitter = jitter;
295
+ self
296
+ }
297
+
298
+ /// Returns the absolute TTL, if set.
299
+ pub fn abs_conn_ttl ( & self ) -> Option < Duration > {
300
+ self . abs_conn_ttl
301
+ }
302
+
303
+ /// Returns the absolute TTL's jitter bound, if set.
304
+ pub fn abs_conn_ttl_jitter ( & self ) -> Option < Duration > {
305
+ self . abs_conn_ttl_jitter
306
+ }
307
+
308
+ /// Returns a new deadline that's TTL (+ random jitter) in the future.
309
+ pub ( crate ) fn new_connection_ttl_deadline ( & self ) -> Option < Instant > {
310
+ if let Some ( ttl) = self . abs_conn_ttl {
311
+ let jitter = if let Some ( jitter) = self . abs_conn_ttl_jitter {
312
+ Duration :: from_secs ( rand:: thread_rng ( ) . gen_range ( 0 ..=jitter. as_secs ( ) ) )
313
+ } else {
314
+ Duration :: ZERO
315
+ } ;
316
+ Some ( Instant :: now ( ) + ttl + jitter)
317
+ } else {
318
+ None
319
+ }
320
+ }
321
+
276
322
/// Pool will recycle inactive connection if it is outside of the lower bound of the pool
277
323
/// and if it is idling longer than this value (defaults to
278
324
/// [`DEFAULT_INACTIVE_CONNECTION_TTL`]).
@@ -359,6 +405,8 @@ impl Default for PoolOpts {
359
405
constraints : DEFAULT_POOL_CONSTRAINTS ,
360
406
inactive_connection_ttl : DEFAULT_INACTIVE_CONNECTION_TTL ,
361
407
ttl_check_interval : DEFAULT_TTL_CHECK_INTERVAL ,
408
+ abs_conn_ttl : None ,
409
+ abs_conn_ttl_jitter : None ,
362
410
reset_connection : true ,
363
411
}
364
412
}
@@ -662,6 +710,49 @@ impl Opts {
662
710
self . inner . mysql_opts . conn_ttl
663
711
}
664
712
713
+ /// The pool will close a connection when this absolute TTL has elapsed.
714
+ /// Disabled by default.
715
+ ///
716
+ /// Enables forced recycling and migration of connections in a guaranteed timeframe.
717
+ /// This TTL bypasses pool constraints and an idle pool can go below the min size.
718
+ ///
719
+ /// # Connection URL
720
+ ///
721
+ /// You can use `abs_conn_ttl` URL parameter to set this value (in seconds). E.g.
722
+ ///
723
+ /// ```
724
+ /// # use mysql_async::*;
725
+ /// # use std::time::Duration;
726
+ /// # fn main() -> Result<()> {
727
+ /// let opts = Opts::from_url("mysql://localhost/db?abs_conn_ttl=86400")?;
728
+ /// assert_eq!(opts.abs_conn_ttl(), Some(Duration::from_secs(24 * 60 * 60)));
729
+ /// # Ok(()) }
730
+ /// ```
731
+ pub fn abs_conn_ttl ( & self ) -> Option < Duration > {
732
+ self . inner . mysql_opts . pool_opts . abs_conn_ttl
733
+ }
734
+
735
+ /// Upper bound of a random value added to the absolute TTL, if enabled.
736
+ /// Disabled by default.
737
+ ///
738
+ /// Should be used to prevent connections from closing at the same time.
739
+ ///
740
+ /// # Connection URL
741
+ ///
742
+ /// You can use `abs_conn_ttl_jitter` URL parameter to set this value (in seconds). E.g.
743
+ ///
744
+ /// ```
745
+ /// # use mysql_async::*;
746
+ /// # use std::time::Duration;
747
+ /// # fn main() -> Result<()> {
748
+ /// let opts = Opts::from_url("mysql://localhost/db?abs_conn_ttl=7200&abs_conn_ttl_jitter=3600")?;
749
+ /// assert_eq!(opts.abs_conn_ttl_jitter(), Some(Duration::from_secs(60 * 60)));
750
+ /// # Ok(()) }
751
+ /// ```
752
+ pub fn abs_conn_ttl_jitter ( & self ) -> Option < Duration > {
753
+ self . inner . mysql_opts . pool_opts . abs_conn_ttl_jitter
754
+ }
755
+
665
756
/// Number of prepared statements cached on the client side (per connection). Defaults to
666
757
/// [`DEFAULT_STMT_CACHE_SIZE`].
667
758
///
@@ -1444,6 +1535,34 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result<MysqlOpts, UrlError> {
1444
1535
} ) ;
1445
1536
}
1446
1537
}
1538
+ } else if key == "abs_conn_ttl" {
1539
+ match u64:: from_str ( & * value) {
1540
+ Ok ( value) => {
1541
+ opts. pool_opts = opts
1542
+ . pool_opts
1543
+ . with_abs_conn_ttl ( Some ( Duration :: from_secs ( value) ) )
1544
+ }
1545
+ _ => {
1546
+ return Err ( UrlError :: InvalidParamValue {
1547
+ param : "abs_conn_ttl" . into ( ) ,
1548
+ value,
1549
+ } ) ;
1550
+ }
1551
+ }
1552
+ } else if key == "abs_conn_ttl_jitter" {
1553
+ match u64:: from_str ( & * value) {
1554
+ Ok ( value) => {
1555
+ opts. pool_opts = opts
1556
+ . pool_opts
1557
+ . with_abs_conn_ttl_jitter ( Some ( Duration :: from_secs ( value) ) )
1558
+ }
1559
+ _ => {
1560
+ return Err ( UrlError :: InvalidParamValue {
1561
+ param : "abs_conn_ttl_jitter" . into ( ) ,
1562
+ value,
1563
+ } ) ;
1564
+ }
1565
+ }
1447
1566
} else if key == "tcp_keepalive" {
1448
1567
match u32:: from_str ( & * value) {
1449
1568
Ok ( value) => opts. tcp_keepalive = Some ( value) ,
@@ -1679,6 +1798,11 @@ mod test {
1679
1798
assert_eq ! ( url_opts. tcp_nodelay( ) , builder_opts. tcp_nodelay( ) ) ;
1680
1799
assert_eq ! ( url_opts. pool_opts( ) , builder_opts. pool_opts( ) ) ;
1681
1800
assert_eq ! ( url_opts. conn_ttl( ) , builder_opts. conn_ttl( ) ) ;
1801
+ assert_eq ! ( url_opts. abs_conn_ttl( ) , builder_opts. abs_conn_ttl( ) ) ;
1802
+ assert_eq ! (
1803
+ url_opts. abs_conn_ttl_jitter( ) ,
1804
+ builder_opts. abs_conn_ttl_jitter( )
1805
+ ) ;
1682
1806
assert_eq ! ( url_opts. stmt_cache_size( ) , builder_opts. stmt_cache_size( ) ) ;
1683
1807
assert_eq ! ( url_opts. ssl_opts( ) , builder_opts. ssl_opts( ) ) ;
1684
1808
assert_eq ! ( url_opts. prefer_socket( ) , builder_opts. prefer_socket( ) ) ;
0 commit comments