diff --git a/crates/radicle-node/src/tests.rs b/crates/radicle-node/src/tests.rs index 3516572d..9e94faf5 100644 --- a/crates/radicle-node/src/tests.rs +++ b/crates/radicle-node/src/tests.rs @@ -1401,6 +1401,48 @@ fn test_maintain_connections_failed_attempt() { assert!(!alice.outbox().any(|o| matches!(o, Io::Connect(_, _)))); } +#[test] +fn test_maintain_connections_same_second_loop() { + use std::io; + use std::sync::Arc; + + let eve = Peer::new("eve", [9, 9, 9, 9]); + let mut alice = Peer::new("alice", [7, 7, 7, 7]); + let reason = DisconnectReason::Dial(Arc::new(io::Error::from(io::ErrorKind::HostUnreachable))); + + alice.connect_to(&eve); + + // Advance clock to make the connection stable. + // This triggers `idle_connections` which sets `last_success` in the DB to the current time (T). + alice.elapse(session::CONNECTION_STABLE_THRESHOLD); + + // Eve disconnects. + // This triggers `maintain_connections`. + alice.disconnected(eve.id(), Link::Outbound, &reason); + + let connects = alice + .outbox() + .filter(|o| matches!(o, Io::Connect(id, _) if id == &eve.id)) + .count(); + assert_eq!(connects, 1, "Alice should attempt to reconnect once"); + + // Simulate the dial failing instantly. + // We DO NOT advance the clock. We just call disconnected again. + // This triggers `maintain_connections` again. + // Now `last_success` is T, and `last_attempt` is T. + alice.disconnected(eve.id(), Link::Outbound, &reason); + + // Check if Alice tries to connect again in the exact same second. + let immediate_retry = alice + .outbox() + .any(|o| matches!(o, Io::Connect(id, _) if id == eve.id)); + + assert!( + !immediate_retry, + "Alice immediately retried a connection when last_success == last_attempt" + ); +} + #[test] fn test_seed_repo_subscribe() { let mut alice = Peer::new("alice", [7, 7, 7, 7]); diff --git a/crates/radicle-protocol/src/service.rs b/crates/radicle-protocol/src/service.rs index ea36e04a..16d71d91 100644 --- a/crates/radicle-protocol/src/service.rs +++ b/crates/radicle-protocol/src/service.rs @@ -2579,7 +2579,7 @@ where // If we succeeded the last time we tried, this is a good address. // If it's been long enough that we failed to connect, we also try again. (Some(success), Some(attempt)) => { - success >= attempt || now - attempt >= CONNECTION_RETRY_DELTA + success > attempt || now - attempt >= CONNECTION_RETRY_DELTA } // If we haven't succeeded yet, and we waited long enough, we can try this address. (None, Some(attempt)) => now - attempt >= CONNECTION_RETRY_DELTA,