@@ -24,6 +24,13 @@ use crate::common::{
2424} ;
2525
2626/// Configuration for the Hyperliquid data client.
27+ ///
28+ /// The `stale_stream_*` options control the stream health monitor. With recovery
29+ /// enabled, a stale stream is warned about first, targeted-resubscribed once per
30+ /// recovery cooldown (preserving its original `l2Book` options), and escalated to
31+ /// a full WebSocket reconnect after `stale_stream_max_targeted_resubscribes`
32+ /// failed attempts; fresh data resets the ladder. See the Hyperliquid integration
33+ /// guide ("Stream health and recovery") for details.
2734#[ derive( Debug , Clone , Serialize , Deserialize , bon:: Builder ) ]
2835#[ serde( default , deny_unknown_fields) ]
2936#[ cfg_attr(
@@ -67,6 +74,18 @@ pub struct HyperliquidDataClientConfig {
6774 /// Cooldown in seconds between stale warnings for the same market-data stream.
6875 #[ builder( default = 60 ) ]
6976 pub stale_stream_warning_cooldown_secs : u64 ,
77+ /// Enables automated stale-stream recovery. Off by default: the stream health
78+ /// monitor warns only and never changes subscriptions.
79+ #[ builder( default = false ) ]
80+ pub stale_stream_recovery_enabled : bool ,
81+ /// Cooldown in seconds between recovery actions for the same market-data stream.
82+ /// Must be positive for recovery to run.
83+ #[ builder( default = 120 ) ]
84+ pub stale_stream_recovery_cooldown_secs : u64 ,
85+ /// Targeted resubscribe attempts for a stale stream before escalating to a
86+ /// full WebSocket reconnect.
87+ #[ builder( default = 3 ) ]
88+ pub stale_stream_max_targeted_resubscribes : u32 ,
7089 /// Interval for refreshing instruments in minutes.
7190 #[ builder( default = 60 ) ]
7291 pub update_instruments_interval_mins : u64 ,
@@ -270,6 +289,9 @@ transport_backend = "tungstenite"
270289 assert_eq ! ( config. stale_stream_receive_timeout_secs, 120 ) ;
271290 assert_eq ! ( config. stream_health_check_interval_secs, 15 ) ;
272291 assert_eq ! ( config. stale_stream_warning_cooldown_secs, 60 ) ;
292+ assert ! ( !config. stale_stream_recovery_enabled) ;
293+ assert_eq ! ( config. stale_stream_recovery_cooldown_secs, 120 ) ;
294+ assert_eq ! ( config. stale_stream_max_targeted_resubscribes, 3 ) ;
273295 }
274296
275297 #[ rstest]
@@ -279,13 +301,19 @@ transport_backend = "tungstenite"
279301stale_stream_receive_timeout_secs = 30
280302stream_health_check_interval_secs = 5
281303stale_stream_warning_cooldown_secs = 20
304+ stale_stream_recovery_enabled = true
305+ stale_stream_recovery_cooldown_secs = 45
306+ stale_stream_max_targeted_resubscribes = 5
282307" ,
283308 )
284309 . unwrap ( ) ;
285310
286311 assert_eq ! ( config. stale_stream_receive_timeout_secs, 30 ) ;
287312 assert_eq ! ( config. stream_health_check_interval_secs, 5 ) ;
288313 assert_eq ! ( config. stale_stream_warning_cooldown_secs, 20 ) ;
314+ assert ! ( config. stale_stream_recovery_enabled) ;
315+ assert_eq ! ( config. stale_stream_recovery_cooldown_secs, 45 ) ;
316+ assert_eq ! ( config. stale_stream_max_targeted_resubscribes, 5 ) ;
289317 }
290318
291319 #[ rstest]
0 commit comments