From 8cea674f58e806c22d2887cff5e6f76bc4dba0db Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Tue, 15 Jul 2025 15:03:11 +0100 Subject: feat(client): skip relays that just timeout Prevent repeated attempts to connect to relays that have previously failed due to connection timeouts within the current session, improving overall performance and reliability. Added a `relays_not_to_retry` map to the `Client` struct to store relays to skip and their reasons. Implemented methods `skip_relay_for_session` and `is_relay_skipped_for_session` to manage this map. Relays are added to the skip list upon connection timeouts. Subsequent attempts to use these skipped relays during the same session will immediately fail with the recorded reason, avoiding unnecessary network calls. Progress bars are updated to reflect skipped relays and their reasons. --- src/lib/client.rs | 130 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 102 insertions(+), 28 deletions(-) diff --git a/src/lib/client.rs b/src/lib/client.rs index 3b613b6..445bf77 100644 --- a/src/lib/client.rs +++ b/src/lib/client.rs @@ -15,11 +15,11 @@ use std::{ fmt::{Display, Write}, fs::create_dir_all, path::Path, - sync::Arc, + sync::{Arc, RwLock}, time::Duration, }; -use anyhow::{Context, Result, bail}; +use anyhow::{Context, Result, anyhow, bail}; use async_trait::async_trait; use console::Style; use futures::{ @@ -60,6 +60,29 @@ pub struct Client { more_fallback_relays: Vec, blaster_relays: Vec, fallback_signer_relays: Vec, + relays_not_to_retry: Arc>>, +} + +impl Client { + /// Marks a relay as skipped for the current session with a given reason. + /// This method encapsulates the write lock for the relays_not_to_retry map. + fn skip_relay_for_session(&self, relay_url: RelayUrl, reason: String) { + self.relays_not_to_retry + .write() + .unwrap() + .insert(relay_url, reason); + } + + /// Checks if a relay should be skipped for the current session and returns + /// the reason if it is. This method encapsulates the read lock for the + /// relays_not_to_retry map. + fn is_relay_skipped_for_session(&self, relay_url: &RelayUrl) -> Option { + self.relays_not_to_retry + .read() + .unwrap() + .get(relay_url) + .cloned() + } } #[cfg_attr(test, automock)] @@ -127,6 +150,7 @@ impl Connect for Client { more_fallback_relays: opts.more_fallback_relays, blaster_relays: opts.blaster_relays, fallback_signer_relays: opts.fallback_signer_relays, + relays_not_to_retry: Arc::new(RwLock::new(HashMap::new())), } } @@ -135,6 +159,9 @@ impl Connect for Client { } async fn connect(&self, relay_url: &RelayUrl) -> Result<()> { + if let Some(reason) = self.is_relay_skipped_for_session(relay_url) { + bail!("{reason}"); + } self.client .add_relay(relay_url) .await @@ -150,6 +177,7 @@ impl Connect for Client { } if !relay.is_connected() { + self.skip_relay_for_session(relay_url.clone(), "connection timeout".to_string()); bail!("connection timeout"); } Ok(()) @@ -244,21 +272,37 @@ impl Connect for Client { } else { None }; + fn update_progress_bar_with_error( + relay_url: &RelayUrl, + pb: Option, + error: &anyhow::Error, + ) { + if let Some(pb) = pb { + pb.set_style(pb_after_style(false)); + pb.set_prefix(format!("{: <11}{}", "error", relay_url)); + pb.finish_with_message( + console::style( + error.to_string().replace("relay pool error:", "error:"), + ) + .for_stderr() + .red() + .to_string(), + ); + } + } + if let Some(reason) = self.is_relay_skipped_for_session(relay.url()) { + update_progress_bar_with_error(relay.url(), pb, &anyhow!("{reason}")); + bail!("{reason}"); + } #[allow(clippy::large_futures)] match get_events_of(relay, filters, &pb).await { Err(error) => { - if let Some(pb) = pb { - pb.set_style(pb_after_style(false)); - pb.set_prefix(format!("{: <11}{}", "error", relay.url())); - pb.finish_with_message( - console::style( - error.to_string().replace("relay pool error:", "error:"), - ) - .for_stderr() - .red() - .to_string(), - ); + // Check error for timeout/connection issues and add to skip list + if error.to_string().contains("connection timeout") { + // Simple check, refine as needed + self.skip_relay_for_session(relay.url().clone(), error.to_string()); } + update_progress_bar_with_error(relay.url(), pb, &error); Err(error) } Ok(res) => { @@ -391,25 +435,55 @@ impl Connect for Client { } else { None }; - + // do here + + fn update_progress_bar_with_error( + relay_column_width: usize, + relay_url: &RelayUrl, + pb: Option, + error: &anyhow::Error, + ) { + if let Some(pb) = pb { + pb.set_style(pb_after_style(false)); + pb.set_prefix( + Style::new() + .color256(247) + .apply_to(format!("{: { - if let Some(pb) = pb { - pb.set_style(pb_after_style(false)); - pb.set_prefix( - dim.apply_to(format!("{: Ok(res), -- cgit v1.2.3