fix(install): mempool no longer blocked by a resyncing ElectrumX + slower podman probes tolerated
Two real install failures from .116 today: (1) the hard "ElectrumX must be running" gate — but mempool-api reconnects to electrum on its own and a resync can take days, so it's now a warning; (2) a 10s podman-ps probe timeout tripped by ElectrumX compaction disk load — now 45s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
b3796546aa
commit
581dbd6337
@ -206,19 +206,24 @@ pub(super) fn check_install_deps(package_id: &str, deps: &RunningDeps) -> Result
|
||||
"BTCPay Server requires a running Bitcoin node (Bitcoin Knots). \
|
||||
Please install and start Bitcoin Knots first."
|
||||
)),
|
||||
"mempool" | "mempool-web" if !deps.has_bitcoin || !deps.has_electrumx => {
|
||||
let mut missing = vec![];
|
||||
if !deps.has_bitcoin {
|
||||
missing.push("Bitcoin Knots");
|
||||
}
|
||||
if !deps.has_electrumx {
|
||||
missing.push("ElectrumX");
|
||||
}
|
||||
Err(anyhow::anyhow!(
|
||||
"Mempool requires {} to be running. Please install and start {} first.",
|
||||
missing.join(" and "),
|
||||
missing.join(" and ")
|
||||
))
|
||||
"mempool" | "mempool-web" if !deps.has_bitcoin => Err(anyhow::anyhow!(
|
||||
"Mempool requires Bitcoin Knots to be running. \
|
||||
Please install and start Bitcoin Knots first."
|
||||
)),
|
||||
// ElectrumX is deliberately NOT a hard gate for mempool: mempool-api
|
||||
// reconnects to electrum on its own (verified live — it retries
|
||||
// ECONNREFUSED in a loop and comes good when electrum starts
|
||||
// listening), and an ElectrumX mid-resync can be legitimately down
|
||||
// for DAYS. The hard gate here blocked repeated mempool installs on
|
||||
// .116 (2026-07-22) while electrumx was compacting. Block/fee views
|
||||
// work from bitcoind immediately; address lookups light up when
|
||||
// ElectrumX finishes.
|
||||
"mempool" | "mempool-web" if !deps.has_electrumx => {
|
||||
info!(
|
||||
"Mempool installing while ElectrumX is not running — \
|
||||
mempool-api reconnects automatically once ElectrumX is up"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
"fedimint" if !deps.has_bitcoin => {
|
||||
info!("Fedimint installing without local Bitcoin node — configure remote Bitcoin RPC in Fedimint guardian setup");
|
||||
@ -298,9 +303,10 @@ fn missing_install_deps(package_id: &str, deps: &RunningDeps) -> Vec<MissingDep>
|
||||
if !deps.has_bitcoin {
|
||||
missing.push(BITCOIN);
|
||||
}
|
||||
if !deps.has_electrumx {
|
||||
missing.push(ELECTRUM);
|
||||
}
|
||||
// ElectrumX intentionally not required — see check_install_deps:
|
||||
// mempool-api reconnects when electrum comes up, and a resyncing
|
||||
// ElectrumX can be down for days (the 3-minute bounded wait here
|
||||
// would still fail the install for no benefit).
|
||||
}
|
||||
// fedimint deliberately absent: check_install_deps allows it without
|
||||
// a local Bitcoin node (remote RPC configured in guardian setup).
|
||||
@ -1111,7 +1117,11 @@ mod tests {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mempool_waits_on_both_bitcoin_and_electrumx() {
|
||||
async fn mempool_waits_on_bitcoin_only() {
|
||||
// ElectrumX is deliberately NOT gated (2026-07-22): a resyncing
|
||||
// ElectrumX can be down for days and mempool-api reconnects on
|
||||
// its own, so the wait only covers Bitcoin — even when electrumx
|
||||
// is installed and stopped.
|
||||
let calls = Arc::new(AtomicU32::new(0));
|
||||
let (labels, sink) = label_sink();
|
||||
let probe_calls = Arc::clone(&calls);
|
||||
@ -1119,8 +1129,8 @@ mod tests {
|
||||
"mempool",
|
||||
move || {
|
||||
let n = probe_calls.fetch_add(1, Ordering::SeqCst);
|
||||
// Bitcoin comes up on probe 2, electrumx on probe 3.
|
||||
async move { Ok(probe(n >= 1, n >= 2, &["bitcoin-knots", "electrumx"])) }
|
||||
// Bitcoin comes up on probe 2; electrumx never does.
|
||||
async move { Ok(probe(n >= 1, false, &["bitcoin-knots", "electrumx"])) }
|
||||
},
|
||||
sink,
|
||||
36,
|
||||
@ -1131,22 +1141,19 @@ mod tests {
|
||||
let labels = labels.lock().unwrap();
|
||||
assert_eq!(
|
||||
labels.as_slice(),
|
||||
&[
|
||||
"Waiting for Bitcoin and ElectrumX to start…".to_string(),
|
||||
"Waiting for ElectrumX to start…".to_string(),
|
||||
]
|
||||
&["Waiting for Bitcoin to start…".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mempool_fails_fast_when_one_dep_is_not_installed() {
|
||||
// Bitcoin is installed (waiting could help) but ElectrumX is not
|
||||
// installed at all — waiting can never satisfy the gate, so fail
|
||||
// fast with the canonical message.
|
||||
async fn mempool_fails_fast_when_bitcoin_is_not_installed() {
|
||||
// Bitcoin isn't installed at all — waiting can never satisfy the
|
||||
// gate, so fail fast with the canonical message. (A missing
|
||||
// ElectrumX no longer blocks anything.)
|
||||
let (labels, sink) = label_sink();
|
||||
let err = wait_for_install_deps(
|
||||
"mempool",
|
||||
|| async { Ok(probe(false, false, &["bitcoin-knots"])) },
|
||||
|| async { Ok(probe(false, false, &["electrumx"])) },
|
||||
sink,
|
||||
36,
|
||||
Duration::ZERO,
|
||||
|
||||
@ -12,7 +12,11 @@ use tracing::info;
|
||||
|
||||
use super::install::{install_log, patch_indeedhub_nostr_provider};
|
||||
|
||||
const PODMAN_STACK_PROBE_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
// 45s, not 10s: under heavy disk load (e.g. an ElectrumX resync/compaction
|
||||
// hammering the same SSD) a plain `podman ps` was observed taking >10s on
|
||||
// .116 (2026-07-22), failing a mempool install at the probe step for no real
|
||||
// reason. Podman being slow is not podman being dead.
|
||||
const PODMAN_STACK_PROBE_TIMEOUT: Duration = Duration::from_secs(45);
|
||||
const PODMAN_STACK_LOG_TIMEOUT: Duration = Duration::from_secs(15);
|
||||
const PODMAN_STACK_PULL_TIMEOUT: Duration = Duration::from_secs(600);
|
||||
const PODMAN_STACK_REMOVE_TIMEOUT: Duration = Duration::from_secs(90);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user