Problem
|
tokio::spawn(async move { |
|
sigterm.recv().await; |
|
|
|
warn!("Received SIGTERM, shutting down..."); |
|
|
|
stop_node_and_teardown( |
|
node.stop_and_wait( |
|
Some("Received SIGTERM signal".to_string()), |
|
Some(Duration::from_secs(10)), |
|
), |
|
&cancel_token, |
|
&graceful_shutdown, |
|
) |
|
.await; |
|
|
|
drain_before_exit(|| store.savepoint()).await; |
|
std::process::exit(SIGTERM_EXIT_CODE); |
|
}); |
install_sigterm_handler as seen above, spawns a task that attempts to perform three ops in order:
stop_node_and_teardown which cancels a cancellation token
drain_before_exit which creates a savepoint in the db
- finally exit with code 143
However, Node::run returns immediately after the app future is cancelled in step (1) above, causing main::start to drop the Tokio runtime, which aborts the sigterm handler clean-up mid task.
This result in the process exiting with code 0 as opposed the intended code 143 as documented
Evidence
A simple binary script was drafted here to verify this race bug
Fix
Add one-shot handover:
- in Handle struct,
sigterm_received: Arc<AtomicBool> and sigterm_done: Arc<Notify>
- in the sigterm handler, call
store(true) before teardown, and notify_one() after drain_before_exit (step 2 above)
- in
Node::run(), if received then await notify and return "SIGTERM" error
- in
main::start, map this "SIGTERM" error to exit(143); keep handler exit(143) for HaltAndWait path where run sleeps forever.
Problem
arc-node/crates/malachite-app/src/node.rs
Lines 1139 to 1156 in 97f8da0
install_sigterm_handleras seen above, spawns a task that attempts to perform three ops in order:stop_node_and_teardownwhichcancelsa cancellation tokendrain_before_exitwhich creates a savepoint in the dbHowever,
Node::runreturns immediately after the app future is cancelled in step (1) above, causingmain::startto drop the Tokio runtime, which aborts the sigterm handler clean-up mid task.Evidence
A simple binary script was drafted here to verify this race bug
Fix
Add one-shot handover:
sigterm_received: Arc<AtomicBool>andsigterm_done: Arc<Notify>store(true)before teardown, andnotify_one()afterdrain_before_exit(step 2 above)Node::run(), if received then await notify and return "SIGTERM" errormain::start, map this "SIGTERM" error to exit(143); keep handler exit(143) for HaltAndWait path where run sleeps forever.