decipherhub / decipherhub/cipherbft
Pruning task could become orphaned on node shutdown
- Dominant language
- Rust
- Stars
- 9
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
The `PruningTask` spawned via `tokio::spawn` could become orphaned or fail silently if the parent node crashes or shuts down unexpectedly.
## Problem Location
`crates/storage/src/pruning.rs:141-231`
## Code Analysis
```rust
// crates/storage/src/pruning.rs:141-149
/// Start the background pruning task
pub fn start(self) -> tokio::task::JoinHandle<()> {
let config = self.config.clone();
let store = Arc::clone(&self.store);
let handle = self.handle;
tokio::spawn(async move {
// pruning loop...
})
}
```
While `PruningHandle` provides a `shutdown()` method, the pattern has issues:
1. **No graceful shutdown guarantee**: If the node panics, `shutdown()` is never called
2. **No completion confirmation**: Callers cannot await proper cleanup
3. **Orphaned state possible**: Mid-pruning crash could leave storage in inconsistent state
## Impact
- Storage inconsistency if pruning is interrupted mid-transaction
- Potential data corruption if MDBX transaction is not properly committed/aborted
- Memory/resource leaks from long-running orphaned tasks
## Recommended Fix
1. Integrate pruning task into structured shutdown via `tokio_util::task::TaskTracker`
2. Implement graceful drain before shutdown
3. Add transaction savepoints for crash recovery
```rust
// Better pattern with TaskTracker
pub struct NodeShutdownCoordinator {
tracker: TaskTracker,
token: CancellationToken,
}
impl NodeShutdownCoordinator {
pub fn spawn_pruning(&self, task: PruningTask) {
self.tracker.spawn(task.run(self.token.clone()));
}
pub async fn shutdown(&self) {
self.token.cancel();
self.tracker.close();
self.tracker.wait().await; // Wait for all tasks to complete
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.