From e706d76aa9bcf9d4fc77a7620d4f904411333d7a Mon Sep 17 00:00:00 2001 From: Dan Cline <6798349+Rjected@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:47:01 +0000 Subject: [PATCH] chore(cli): support ctrl-C in reth prune (#21759) --- crates/cli/commands/src/prune.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/crates/cli/commands/src/prune.rs b/crates/cli/commands/src/prune.rs index 3f381c6989..3a5fb1d546 100644 --- a/crates/cli/commands/src/prune.rs +++ b/crates/cli/commands/src/prune.rs @@ -4,6 +4,7 @@ use clap::Parser; use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks}; use reth_cli::chainspec::ChainSpecParser; use reth_cli_runner::CliContext; +use reth_cli_util::cancellation::CancellationToken; use reth_node_builder::common::metrics_hooks; use reth_node_core::{args::MetricArgs, version::version_metadata}; use reth_node_metrics::{ @@ -50,7 +51,7 @@ impl> PruneComma build_profile: version_metadata().build_profile_name.as_ref(), }, ChainSpecInfo { name: provider_factory.chain_spec().chain().to_string() }, - ctx.task_executor, + ctx.task_executor.clone(), metrics_hooks(&provider_factory), data_dir.pprof_dumps(), ); @@ -70,6 +71,14 @@ impl> PruneComma if let Some(prune_tip) = lowest_static_file_height { info!(target: "reth::cli", ?prune_tip, ?config, "Pruning data from database..."); + // Set up cancellation token for graceful shutdown on Ctrl+C + let cancellation = CancellationToken::new(); + let cancellation_clone = cancellation.clone(); + ctx.task_executor.spawn_critical("prune-ctrl-c", async move { + tokio::signal::ctrl_c().await.expect("failed to listen for ctrl-c"); + cancellation_clone.cancel(); + }); + // Use batched pruning with a limit to bound memory, running in a loop until complete. const DELETE_LIMIT: usize = 200_000; let mut pruner = PrunerBuilder::new(config) @@ -78,6 +87,11 @@ impl> PruneComma let mut total_pruned = 0usize; loop { + if cancellation.is_cancelled() { + info!(target: "reth::cli", total_pruned, "Pruning interrupted by user"); + break; + } + let output = pruner.run(prune_tip)?; let batch_pruned: usize = output.segments.iter().map(|(_, seg)| seg.pruned).sum(); total_pruned = total_pruned.saturating_add(batch_pruned); @@ -88,6 +102,7 @@ impl> PruneComma output.segments.iter().all(|(_, seg)| seg.progress.is_finished()); if all_segments_finished { + info!(target: "reth::cli", total_pruned, "Pruned data from database"); break; } @@ -105,7 +120,6 @@ impl> PruneComma "Pruning batch complete, continuing..." ); } - info!(target: "reth::cli", total_pruned, "Pruned data from database"); } Ok(())