@@ -59,77 +59,121 @@ impl MasternodeCache {
5959
6060 async fn update_cache ( & self ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
6161 println ! ( "Updating masternode cache..." ) ;
62-
62+
63+ // Wrap the entire operation in a timeout (30 seconds)
64+ let result = tokio:: time:: timeout (
65+ tokio:: time:: Duration :: from_secs ( 30 ) ,
66+ self . update_cache_internal ( )
67+ ) . await ;
68+
69+ match result {
70+ Ok ( Ok ( ( ) ) ) => Ok ( ( ) ) ,
71+ Ok ( Err ( e) ) => Err ( e) ,
72+ Err ( _) => {
73+ eprintln ! ( "⚠️ CACHE UPDATE TIMED OUT after 30 seconds - this indicates network issues or too many slow nodes" ) ;
74+ Err ( "Cache update timed out after 30 seconds" . into ( ) )
75+ }
76+ }
77+ }
78+
79+ async fn update_cache_internal ( & self ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
6380 // Fetch new data
6481 let mut masternodes = masternode_loader:: load_masternode_list ( & self . config ) . await ?;
65-
82+
6683 println ! ( "Checking version for {} Evo masternodes..." , masternodes. len( ) ) ;
6784
6885 // Check version for each masternode
6986 let check_tasks: Vec < _ > = masternodes. iter ( ) . enumerate ( ) . map ( |( idx, node) | {
7087 let address = node. address . clone ( ) ;
7188 let status = node. status . clone ( ) ;
72-
89+ let config = self . config . clone ( ) ;
90+
7391 async move {
92+ let start = std:: time:: Instant :: now ( ) ;
93+
7494 // Skip POSE_BANNED nodes
7595 if status == "POSE_BANNED" {
7696 println ! ( "⏭️ Node {} at {} - skipping (POSE_BANNED)" , idx, address) ;
77- return ( idx, "fail" . to_string ( ) , None , None ) ;
97+ return ( idx, "fail" . to_string ( ) , None , None , start . elapsed ( ) ) ;
7898 }
79-
99+
80100 // Parse address to get IP and port
81101 let parts: Vec < & str > = address. split ( ':' ) . collect ( ) ;
82102 if parts. len ( ) != 2 {
83103 println ! ( "❌ Node {} at {} - invalid address format" , idx, address) ;
84- return ( idx, "fail" . to_string ( ) , None , None ) ;
104+ return ( idx, "fail" . to_string ( ) , None , None , start . elapsed ( ) ) ;
85105 }
86-
106+
87107 let ip = parts[ 0 ] ;
88- let port = self . config . get_dapi_port ( ) ;
89-
108+ let port = config. get_dapi_port ( ) ;
109+
90110 println ! ( "🔍 Node {} at {} - checking version..." , idx, address) ;
91-
92- // Check version with additional timeout wrapper (3 seconds total)
93- match tokio:: time:: timeout (
94- tokio:: time:: Duration :: from_secs ( 3 ) ,
111+
112+ // Check version with additional timeout wrapper (2 seconds total)
113+ let result = match tokio:: time:: timeout (
114+ tokio:: time:: Duration :: from_secs ( 2 ) ,
95115 grpc_client:: check_node_version ( ip, port)
96116 ) . await {
97117 Ok ( Ok ( result) ) => {
118+ let elapsed = start. elapsed ( ) ;
98119 if result. success {
99- println ! ( "✓ Node {} at {} - version 2.0+ (DAPI: {:?}, Drive: {:?})" ,
100- idx, address, result. dapi_version, result. drive_version) ;
101- ( idx, "success" . to_string ( ) , result. dapi_version , result. drive_version )
120+ println ! ( "✓ Node {} at {} - version 2.0+ (DAPI: {:?}, Drive: {:?}) [took {:?}]" ,
121+ idx, address, result. dapi_version, result. drive_version, elapsed ) ;
122+ ( idx, "success" . to_string ( ) , result. dapi_version , result. drive_version , elapsed )
102123 } else {
103- println ! ( "✗ Node {} at {} - version < 2.0 (DAPI: {:?}, Drive: {:?})" ,
104- idx, address, result. dapi_version, result. drive_version) ;
105- ( idx, "fail" . to_string ( ) , result. dapi_version , result. drive_version )
124+ println ! ( "✗ Node {} at {} - version < 2.0 (DAPI: {:?}, Drive: {:?}) [took {:?}]" ,
125+ idx, address, result. dapi_version, result. drive_version, elapsed ) ;
126+ ( idx, "fail" . to_string ( ) , result. dapi_version , result. drive_version , elapsed )
106127 }
107128 } ,
108129 Ok ( Err ( e) ) => {
109- println ! ( "✗ Node {} at {} - error: {}" , idx, address, e) ;
110- ( idx, "fail" . to_string ( ) , None , None )
130+ let elapsed = start. elapsed ( ) ;
131+ println ! ( "✗ Node {} at {} - error: {} [took {:?}]" , idx, address, e, elapsed) ;
132+ ( idx, "fail" . to_string ( ) , None , None , elapsed)
111133 } ,
112134 Err ( _) => {
113- println ! ( "✗ Node {} at {} - timeout after 3 seconds" , idx, address) ;
114- ( idx, "fail" . to_string ( ) , None , None )
135+ let elapsed = start. elapsed ( ) ;
136+ println ! ( "⏱️ Node {} at {} - TIMEOUT after {:?} ⚠️ THIS NODE IS SLOW!" , idx, address, elapsed) ;
137+ ( idx, "fail" . to_string ( ) , None , None , elapsed)
115138 } ,
116- }
139+ } ;
140+ result
117141 }
118142 } ) . collect ( ) ;
119143
120144 // Execute all version checks concurrently
145+ let overall_start = std:: time:: Instant :: now ( ) ;
121146 let results = futures:: future:: join_all ( check_tasks) . await ;
122-
147+ let total_elapsed = overall_start. elapsed ( ) ;
148+
149+ // Track slow nodes
150+ let mut slow_nodes: Vec < ( usize , String , std:: time:: Duration ) > = vec ! [ ] ;
151+
123152 // Update the version_check field and version info for each masternode
124- for ( idx, version_check, dapi_version, drive_version) in results {
153+ for ( idx, version_check, dapi_version, drive_version, elapsed ) in results {
125154 masternodes[ idx] . version_check = version_check;
126155 masternodes[ idx] . dapi_version = dapi_version;
127156 masternodes[ idx] . drive_version = drive_version;
157+
158+ // Track nodes that took more than 2 seconds
159+ if elapsed. as_secs ( ) >= 2 {
160+ slow_nodes. push ( ( idx, masternodes[ idx] . address . clone ( ) , elapsed) ) ;
161+ }
128162 }
129-
163+
130164 let success_count = masternodes. iter ( ) . filter ( |n| n. version_check == "success" ) . count ( ) ;
131165 let fail_count = masternodes. iter ( ) . filter ( |n| n. version_check == "fail" ) . count ( ) ;
132- println ! ( "Version check complete: {} success, {} fail" , success_count, fail_count) ;
166+ println ! ( "Version check complete: {} success, {} fail (total time: {:?})" , success_count, fail_count, total_elapsed) ;
167+
168+ // Report slow nodes
169+ if !slow_nodes. is_empty ( ) {
170+ println ! ( "\n 🐌 SLOW NODES DETECTED ({} nodes took >2s):" , slow_nodes. len( ) ) ;
171+ slow_nodes. sort_by ( |a, b| b. 2 . cmp ( & a. 2 ) ) ; // Sort by duration, slowest first
172+ for ( idx, address, duration) in slow_nodes. iter ( ) . take ( 10 ) {
173+ println ! ( " Node {} at {} took {:?}" , idx, address, duration) ;
174+ }
175+ println ! ( ) ;
176+ }
133177
134178 // Update the cache
135179 {
0 commit comments