From 3954355a7535811378be8d386d4dad2e18add8db Mon Sep 17 00:00:00 2001 From: tosynthegeek Date: Mon, 30 Jun 2025 09:04:34 +0100 Subject: [PATCH] Add exponential backoff for sync failures Previously, chain synchronization failures would retry immediately without any delay, which could lead to tight retry loops and high CPU usage during failures. This change introduces exponential backoff for transient errors, starting at 2 seconds and doubling each time up to a maximum of 300 seconds. Persistent errors also now delay retries by the maximum backoff duration to prevent rapid loops while maintaining eventual recovery. Fixes #587 --- src/chain/mod.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/chain/mod.rs b/src/chain/mod.rs index fac8b0e6c..df10ecac2 100644 --- a/src/chain/mod.rs +++ b/src/chain/mod.rs @@ -36,7 +36,7 @@ use lightning_transaction_sync::EsploraSyncClient; use lightning_block_sync::gossip::UtxoSource; use lightning_block_sync::init::{synchronize_listeners, validate_best_block_header}; use lightning_block_sync::poll::{ChainPoller, ChainTip, ValidatedBlockHeader}; -use lightning_block_sync::SpvClient; +use lightning_block_sync::{BlockSourceErrorKind, SpvClient}; use bdk_esplora::EsploraAsyncExt; use bdk_wallet::Update as BdkUpdate; @@ -425,6 +425,9 @@ impl ChainSource { "Starting initial synchronization of chain listeners. This might take a while..", ); + let mut backoff = CHAIN_POLLING_INTERVAL_SECS; + const MAX_BACKOFF_SECS: u64 = 300; + loop { let channel_manager_best_block_hash = channel_manager.current_best_block().block_hash; @@ -504,8 +507,24 @@ impl ChainSource { Err(e) => { log_error!(logger, "Failed to synchronize chain listeners: {:?}", e); - tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS)) - .await; + if e.kind() == BlockSourceErrorKind::Transient { + log_info!( + logger, + "Transient error syncing chain listeners: {:?}. Retrying in {} seconds.", + e, + backoff + ); + tokio::time::sleep(Duration::from_secs(backoff)).await; + backoff = std::cmp::min(backoff * 2, MAX_BACKOFF_SECS); + } else { + log_error!( + logger, + "Persistent error syncing chain listeners: {:?}. Retrying in {} seconds.", + e, + MAX_BACKOFF_SECS + ); + tokio::time::sleep(Duration::from_secs(MAX_BACKOFF_SECS)).await; + } }, } }