From faebb30d08151ec6bc654da927c084d7aa21656a Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 28 Oct 2025 13:41:05 -0500 Subject: [PATCH] Fix bitcoind shutdown hang Previously, the shutdown process could hang when using the bitcoind backend because the syncing process was not always checking if we had received the shutdown signal. Now with any future we call during the sync process we will use a `tokio::select!` to make sure we abort early if we receive a stop signal. --- src/chain/bitcoind.rs | 70 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/src/chain/bitcoind.rs b/src/chain/bitcoind.rs index a0151e5a2..4b7cd588f 100644 --- a/src/chain/bitcoind.rs +++ b/src/chain/bitcoind.rs @@ -147,6 +147,12 @@ impl BitcoindChainSource { const MAX_BACKOFF_SECS: u64 = 300; loop { + // if the stop_sync_sender has been dropped, we should just exit + if stop_sync_receiver.has_changed().unwrap_or(true) { + log_trace!(self.logger, "Stopping initial chain sync."); + return; + } + let channel_manager_best_block_hash = channel_manager.current_best_block().block_hash; let sweeper_best_block_hash = output_sweeper.current_best_block().block_hash; let onchain_wallet_best_block_hash = @@ -226,7 +232,18 @@ impl BitcoindChainSource { e, backoff ); - tokio::time::sleep(Duration::from_secs(backoff)).await; + // Sleep with stop signal check to allow immediate shutdown + tokio::select! { + biased; + _ = stop_sync_receiver.changed() => { + log_trace!( + self.logger, + "Stopping initial chain sync.", + ); + return; + } + _ = tokio::time::sleep(Duration::from_secs(backoff)) => {} + } backoff = std::cmp::min(backoff * 2, MAX_BACKOFF_SECS); } else { log_error!( @@ -235,7 +252,18 @@ impl BitcoindChainSource { e, MAX_BACKOFF_SECS ); - tokio::time::sleep(Duration::from_secs(MAX_BACKOFF_SECS)).await; + // Sleep with stop signal check to allow immediate shutdown + tokio::select! { + biased; + _ = stop_sync_receiver.changed() => { + log_trace!( + self.logger, + "Stopping initial chain sync during backoff.", + ); + return; + } + _ = tokio::time::sleep(Duration::from_secs(MAX_BACKOFF_SECS)) => {} + } } }, } @@ -260,6 +288,7 @@ impl BitcoindChainSource { let mut last_best_block_hash = None; loop { tokio::select! { + biased; _ = stop_sync_receiver.changed() => { log_trace!( self.logger, @@ -268,17 +297,38 @@ impl BitcoindChainSource { return; } _ = chain_polling_interval.tick() => { - let _ = self.poll_and_update_listeners( - Arc::clone(&channel_manager), - Arc::clone(&chain_monitor), - Arc::clone(&output_sweeper) - ).await; + tokio::select! { + biased; + _ = stop_sync_receiver.changed() => { + log_trace!( + self.logger, + "Stopping polling for new chain data.", + ); + return; + } + _ = self.poll_and_update_listeners( + Arc::clone(&channel_manager), + Arc::clone(&chain_monitor), + Arc::clone(&output_sweeper) + ) => {} + } } _ = fee_rate_update_interval.tick() => { if last_best_block_hash != Some(channel_manager.current_best_block().block_hash) { - let update_res = self.update_fee_rate_estimates().await; - if update_res.is_ok() { - last_best_block_hash = Some(channel_manager.current_best_block().block_hash); + tokio::select! { + biased; + _ = stop_sync_receiver.changed() => { + log_trace!( + self.logger, + "Stopping polling for new chain data.", + ); + return; + } + update_res = self.update_fee_rate_estimates() => { + if update_res.is_ok() { + last_best_block_hash = Some(channel_manager.current_best_block().block_hash); + } + } } } }