@@ -1808,11 +1808,17 @@ impl DaemonState {
18081808
18091809 /// Close only the failed peer's cached connection. The next probe opens a new
18101810 /// connection and refreshes discovery without touching any other peer.
1811- async fn recover_unreachable_peer ( & self , peer_id : EndpointId , label : & str , attempt : usize ) {
1811+ async fn recover_unreachable_peer (
1812+ & self ,
1813+ peer_id : EndpointId ,
1814+ label : & str ,
1815+ attempt : usize ,
1816+ failed_probe_started : Instant ,
1817+ ) {
18121818 let endpoint = self . endpoint_handle ( ) ;
18131819 let redialled = self
18141820 . peer_connections
1815- . redial ( peer_id, b"peer health recovery" )
1821+ . redial_opened_before ( peer_id, b"peer health recovery" , failed_probe_started )
18161822 . await ;
18171823 warn ! (
18181824 target: VALIDATION_LOG_TARGET ,
@@ -2760,9 +2766,10 @@ async fn run_peer_health_loop_with(
27602766 "recent application traffic proved peer liveness"
27612767 ) ,
27622768 }
2763- round. push( ( peer_id, label, true , peer. roaming) ) ;
2769+ round. push( ( peer_id, label, true , peer. roaming, Instant :: now ( ) ) ) ;
27642770 continue ;
27652771 }
2772+ let probe_started = Instant :: now( ) ;
27662773 let health = state. check_peer_reachability( & peer) . await ;
27672774 match peer_probe_log_action(
27682775 & mut roaming_away,
@@ -2852,14 +2859,20 @@ async fn run_peer_health_loop_with(
28522859 "persistent path degradation closed the shared peer connection"
28532860 ) ;
28542861 }
2855- round. push( ( peer_id, label, health. reachable, peer. roaming) ) ;
2862+ round. push( (
2863+ peer_id,
2864+ label,
2865+ health. reachable,
2866+ peer. roaming,
2867+ probe_started,
2868+ ) ) ;
28562869 }
2857- for ( peer_id, label, reachable, roaming) in round {
2870+ for ( peer_id, label, reachable, roaming, probe_started ) in round {
28582871 if let PeerHealthAction :: Recover { attempt } =
28592872 tracker. on_probe( peer_id, reachable, roaming, Instant :: now( ) )
28602873 {
28612874 state
2862- . recover_unreachable_peer( peer_id, & label, attempt)
2875+ . recover_unreachable_peer( peer_id, & label, attempt, probe_started )
28632876 . await ;
28642877 }
28652878 }
@@ -5914,14 +5927,18 @@ mod tests {
59145927 let bluey = iroh:: SecretKey :: generate ( ) . public ( ) ;
59155928 let before = state. endpoint_handle ( ) . generation ;
59165929
5917- state. recover_unreachable_peer ( bluey, "bluey" , 3 ) . await ;
5930+ state
5931+ . recover_unreachable_peer ( bluey, "bluey" , 3 , Instant :: now ( ) )
5932+ . await ;
59185933 assert_eq ! (
59195934 state. endpoint_handle( ) . generation,
59205935 before,
59215936 "one peer's absence must never replace the shared endpoint"
59225937 ) ;
59235938
5924- state. recover_unreachable_peer ( bluey, "bluey" , 100 ) . await ;
5939+ state
5940+ . recover_unreachable_peer ( bluey, "bluey" , 100 , Instant :: now ( ) )
5941+ . await ;
59255942 assert_eq ! ( state. endpoint_handle( ) . generation, before) ;
59265943
59275944 node. shutdown ( ) . await ?;
@@ -5956,7 +5973,7 @@ mod tests {
59565973 } ;
59575974 assert_eq ! ( attempt, expected_attempt) ;
59585975 state
5959- . recover_unreachable_peer ( bluey, "bluey" , attempt)
5976+ . recover_unreachable_peer ( bluey, "bluey" , attempt, now )
59605977 . await ;
59615978 }
59625979
@@ -5972,7 +5989,7 @@ mod tests {
59725989 } ;
59735990 assert_eq ! ( attempt, OLD_RECYCLE_ATTEMPT ) ;
59745991 state
5975- . recover_unreachable_peer ( bluey, "bluey" , attempt)
5992+ . recover_unreachable_peer ( bluey, "bluey" , attempt, now )
59765993 . await ;
59775994
59785995 assert_eq ! (
@@ -6971,7 +6988,7 @@ mod tests {
69716988 let absent = iroh:: SecretKey :: generate ( ) . public ( ) ;
69726989 let drops_before = * state. tunnel_drop_tx . borrow ( ) ;
69736990 state
6974- . recover_unreachable_peer ( absent, "absent-peer" , 100 )
6991+ . recover_unreachable_peer ( absent, "absent-peer" , 100 , Instant :: now ( ) )
69756992 . await ;
69766993 let drops_after = * state. tunnel_drop_tx . borrow ( ) ;
69776994 assert_eq ! ( drops_after, drops_before) ;
@@ -7562,7 +7579,12 @@ mod tests {
75627579 . await ;
75637580 // One peer away while the other answers: cheap recovery, no teardown.
75647581 state
7565- . recover_unreachable_peer ( iroh:: SecretKey :: generate ( ) . public ( ) , "absent" , 3 )
7582+ . recover_unreachable_peer (
7583+ iroh:: SecretKey :: generate ( ) . public ( ) ,
7584+ "absent" ,
7585+ 3 ,
7586+ Instant :: now ( ) ,
7587+ )
75667588 . await ;
75677589 // And a recycle attempt, which is what a failed health poll ends in.
75687590 let outcome = state
0 commit comments