diff --git a/src/tool/subcommands/api_cmd/generate_test_snapshot.rs b/src/tool/subcommands/api_cmd/generate_test_snapshot.rs index ec15584c689..0e439b7fd5e 100644 --- a/src/tool/subcommands/api_cmd/generate_test_snapshot.rs +++ b/src/tool/subcommands/api_cmd/generate_test_snapshot.rs @@ -119,13 +119,17 @@ async fn ctx( read_genesis_header(None, chain_config.genesis_bytes(&db).await?.as_deref(), &db).await?; let chain_store = ChainStore::new(db.clone(), chain_config, genesis_header)?; let state_manager = StateManager::new(chain_store.shallow_clone())?; + let mut services: JoinSet> = JoinSet::new(); let message_pool = MessagePool::new( chain_store, network_send.clone(), Default::default(), state_manager.chain_config().clone(), - &mut JoinSet::new(), + &mut services, )?; + // See `super::test_snapshot::drain_mpool_services` for rationale. + services.abort_all(); + tokio::spawn(super::test_snapshot::drain_mpool_services(services)); let peer_manager = Arc::new(PeerManager::default()); let sync_network_context = diff --git a/src/tool/subcommands/api_cmd/test_snapshot.rs b/src/tool/subcommands/api_cmd/test_snapshot.rs index 4149f33dba8..37a386eeb40 100644 --- a/src/tool/subcommands/api_cmd/test_snapshot.rs +++ b/src/tool/subcommands/api_cmd/test_snapshot.rs @@ -144,13 +144,21 @@ async fn ctx( read_genesis_header(None, chain_config.genesis_bytes(&db).await?.as_deref(), &db).await?; let chain_store = ChainStore::new(db, chain_config, genesis_header.clone())?; let state_manager = StateManager::new(chain_store.shallow_clone()).unwrap(); + let mut services: JoinSet> = JoinSet::new(); let message_pool = MessagePool::new( chain_store, network_send.clone(), Default::default(), state_manager.chain_config().clone(), - &mut JoinSet::new(), + &mut services, )?; + // The mpool services are not needed in this snapshot test context; abort + // them right away so they don't compete with the test for runtime time + // (the inherited `&mut JoinSet::new()` pattern was a temporary that + // dropped — same end state). The detached drain still polls the aborted + // set so any pre-abort error or panic is surfaced rather than dropped. + services.abort_all(); + tokio::spawn(drain_mpool_services(services)); let peer_manager = Arc::new(PeerManager::default()); let sync_network_context = @@ -176,6 +184,21 @@ async fn ctx( Ok((rpc_state, network_rx, shutdown_recv)) } +/// Drains a `MessagePool` service [`JoinSet`] to completion, logging any +/// errors or panics it produces. Intended to be used with `tokio::spawn` from +/// test-utility `ctx()` helpers so that service-task errors are surfaced +/// instead of being silently dropped when the `JoinSet` is dropped. +pub(super) async fn drain_mpool_services(mut services: JoinSet>) { + while let Some(result) = services.join_next().await { + match result { + Ok(Ok(())) => {} + Ok(Err(e)) => tracing::warn!("message pool service task error: {e:#}"), + Err(je) if je.is_cancelled() => {} + Err(je) => tracing::warn!("message pool service task panicked: {je}"), + } + } +} + #[cfg(test)] mod tests { use super::*;