From 3de576141bba2247b0a0815918d730bcb0e7e9db Mon Sep 17 00:00:00 2001 From: atlas Date: Sat, 4 Jul 2026 12:40:00 +0200 Subject: [PATCH] refactor: extract bring_up_secondary_with_retry (fix clippy too_many_lines + needless_continue) --- hive-matrix-mcp/src/main.rs | 133 ++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 60 deletions(-) diff --git a/hive-matrix-mcp/src/main.rs b/hive-matrix-mcp/src/main.rs index db60ae99..e15d0983 100644 --- a/hive-matrix-mcp/src/main.rs +++ b/hive-matrix-mcp/src/main.rs @@ -109,67 +109,12 @@ async fn main() -> Result<()> { // before being skipped for this daemon lifetime. Err(e) if is_primary => return Err(e.context("bring up primary matrix account")), Err(e) => { - // Permanent failure (bad/expired token already removed): - // no point retrying. - if e.downcast_ref::().is_some() { - tracing::error!( - account = %cfg.name, - error = %format!("{e:#}"), - "secondary matrix account: permanent failure; skipping" - ); - continue; + if let Some((client, sync_loop)) = + bring_up_secondary_with_retry(&cfg, &hyperhive_socket, tag, e).await + { + registry.insert(cfg.name, client); + sync_loops.push(sync_loop); } - // Transient failure: retry with backoff before giving up. - tracing::warn!( - account = %cfg.name, - error = %format!("{e:#}"), - "secondary matrix account bring-up failed (transient); will retry" - ); - let mut recovered = false; - for &delay in SECONDARY_RETRY_DELAYS_SECS { - tracing::info!( - account = %cfg.name, - delay_s = delay, - "retrying secondary account bring-up after backoff" - ); - tokio::time::sleep(std::time::Duration::from_secs(delay)).await; - match bring_up_account(&cfg, &hyperhive_socket, tag.clone(), false).await { - Ok(Some((client, sync_loop))) => { - tracing::info!(account = %cfg.name, "secondary matrix account recovered"); - registry.insert(cfg.name.clone(), client); - sync_loops.push(sync_loop); - recovered = true; - break; - } - Ok(None) => { - tracing::warn!(account = %cfg.name, "secondary matrix account has no token; skipping"); - break; - } - Err(re) if re.downcast_ref::().is_some() => { - tracing::error!( - account = %cfg.name, - error = %format!("{re:#}"), - "secondary matrix account: permanent failure on retry; skipping" - ); - break; - } - Err(re) => { - tracing::warn!( - account = %cfg.name, - error = %format!("{re:#}"), - "secondary matrix account bring-up still failing (transient)" - ); - } - } - } - if !recovered { - tracing::error!( - account = %cfg.name, - retries = SECONDARY_RETRY_DELAYS_SECS.len(), - "secondary matrix account failed after all retries; skipping for this daemon lifetime" - ); - } - continue; } } } @@ -237,6 +182,74 @@ async fn main() -> Result<()> { Ok(()) } +/// Try to bring up a secondary account, retrying with exponential backoff +/// on transient failures (anything that is NOT a `PermanentBringUpError`). +/// Returns `Some((client, sync_loop))` on success, or `None` to signal +/// that the account should be skipped for this daemon lifetime (permanent +/// failure, no token, or all retries exhausted). +async fn bring_up_secondary_with_retry( + cfg: &AccountCfg, + hyperhive_socket: &std::path::Path, + tag: Option, + first_error: anyhow::Error, +) -> Option<(Client, SyncLoop)> { + // Permanent failure: the token was invalid/expired and has already been + // removed from disk. Retrying won't help — skip immediately. + if first_error.downcast_ref::().is_some() { + tracing::error!( + account = %cfg.name, + error = %format!("{first_error:#}"), + "secondary matrix account: permanent failure; skipping" + ); + return None; + } + // Transient failure (network/DNS/homeserver 5xx): retry with backoff. + tracing::warn!( + account = %cfg.name, + error = %format!("{first_error:#}"), + "secondary matrix account bring-up failed (transient); will retry" + ); + for &delay in SECONDARY_RETRY_DELAYS_SECS { + tracing::info!( + account = %cfg.name, + delay_s = delay, + "retrying secondary account bring-up after backoff" + ); + tokio::time::sleep(std::time::Duration::from_secs(delay)).await; + match bring_up_account(cfg, hyperhive_socket, tag.clone(), false).await { + Ok(Some((client, sync_loop))) => { + tracing::info!(account = %cfg.name, "secondary matrix account recovered"); + return Some((client, sync_loop)); + } + Ok(None) => { + tracing::warn!(account = %cfg.name, "secondary matrix account has no token; skipping"); + return None; + } + Err(re) if re.downcast_ref::().is_some() => { + tracing::error!( + account = %cfg.name, + error = %format!("{re:#}"), + "secondary matrix account: permanent failure on retry; skipping" + ); + return None; + } + Err(re) => { + tracing::warn!( + account = %cfg.name, + error = %format!("{re:#}"), + "secondary matrix account bring-up still failing (transient)" + ); + } + } + } + tracing::error!( + account = %cfg.name, + retries = SECONDARY_RETRY_DELAYS_SECS.len(), + "secondary matrix account failed after all retries; skipping for this daemon lifetime" + ); + None +} + /// Restore one account's client (when its token exists), install its /// message handler, and build its sync loop. Returns /// `Ok(Some((client, sync_loop)))` when the account came up, `Ok(None)`