@@ -15,6 +15,7 @@ use std::{
1515 net:: { IpAddr , SocketAddr } ,
1616 path:: { Path , PathBuf } ,
1717 sync:: Arc ,
18+ sync:: atomic:: { AtomicU32 , Ordering } ,
1819} ;
1920use tokio_util:: sync:: CancellationToken ;
2021
@@ -30,7 +31,7 @@ use ethlambda_types::{
3031 state:: { State , ValidatorPubkeyBytes } ,
3132} ;
3233use serde:: Deserialize ;
33- use tracing:: { error, info} ;
34+ use tracing:: { error, info, warn } ;
3435use tracing_subscriber:: { EnvFilter , Layer , Registry , layer:: SubscriberExt } ;
3536
3637use ethlambda_blockchain:: BlockChain ;
@@ -222,8 +223,32 @@ async fn main() -> eyre::Result<()> {
222223
223224 info ! ( "Node initialized" ) ;
224225
225- tokio:: signal:: ctrl_c ( ) . await . ok ( ) ;
226- info ! ( "Shutdown signal received, stopping actors and servers..." ) ;
226+ let signal_count = Arc :: new ( AtomicU32 :: new ( 0 ) ) ;
227+ let signal_count_clone = signal_count. clone ( ) ;
228+
229+ // Handle multiple Ctrl+C signals:
230+ // 1st Ctrl+C: graceful shutdown
231+ // 2nd Ctrl+C: force exit immediately
232+ tokio:: spawn ( async move {
233+ loop {
234+ tokio:: signal:: ctrl_c ( ) . await . ok ( ) ;
235+ let count = signal_count_clone. fetch_add ( 1 , Ordering :: SeqCst ) + 1 ;
236+ if count == 1 {
237+ info ! ( "Shutdown signal received, stopping actors and servers..." ) ;
238+ } else {
239+ warn ! ( "Force shutdown requested, exiting immediately" ) ;
240+ std:: process:: exit ( 1 ) ;
241+ }
242+ }
243+ } ) ;
244+
245+ // Wait for first signal
246+ loop {
247+ if signal_count. load ( Ordering :: SeqCst ) > 0 {
248+ break ;
249+ }
250+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_millis ( 100 ) ) . await ;
251+ }
227252
228253 let blockchain_ref = blockchain. actor_ref ( ) . clone ( ) ;
229254 let p2p_ref = p2p. actor_ref ( ) . clone ( ) ;
0 commit comments