Skip to content

Fire-and-forget tokio::spawn pattern lacks panic detection #53

@qj0r9j0vc2

Description

@qj0r9j0vc2

Summary

Multiple locations use tokio::spawn without collecting the JoinHandle, making it impossible to detect task panics or failures.

Problem Locations

  • crates/consensus/src/host.rs:884 - DCL cut processing task
  • crates/node/src/network.rs:106,112 - Network listener and connection handlers
  • crates/node/src/node.rs:276 - Peer connection retry task

Code Example

// crates/consensus/src/host.rs:882-890
// Spawn background task to process DCL cuts
let value_builder_for_cuts = Arc::clone(&value_builder);
tokio::spawn(async move {  // JoinHandle is dropped immediately
    while let Some(cut) = cut_rx.recv().await {
        let height = ConsensusHeight::from(cut.height);
        value_builder_for_cuts.store_cut(height, cut).await;
    }
    warn!("Host: DCL cut receiver closed");
});

Impact

  • Silent Failures: If a spawned task panics, no error is reported
  • Debugging Difficulty: No way to know if background tasks are running correctly
  • Resource Leaks: Panic in spawned task may leave resources in inconsistent state

Recommended Fix

  1. Collect JoinHandle in a Vec<JoinHandle<()>> or JoinSet
  2. Monitor handles for completion/panic in a supervisor task
  3. Use tokio::select! to handle task failures gracefully
// Better pattern:
let mut join_set = JoinSet::new();
join_set.spawn(async move {
    // task code
});

// Later, monitor for failures:
while let Some(result) = join_set.join_next().await {
    if let Err(e) = result {
        error!("Background task failed: {:?}", e);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions