1
1
use anyhow:: { anyhow, Context } ;
2
2
use clap:: { CommandFactory , Parser , Subcommand } ;
3
3
use slog:: { Drain , Level , Logger } ;
4
- use slog_scope:: { error, info, warn } ;
4
+ use slog_scope:: { error, info} ;
5
5
use std:: {
6
6
fmt, fs,
7
7
path:: { Path , PathBuf } ,
8
8
process:: { ExitCode , Termination } ,
9
9
sync:: Arc ,
10
10
time:: Duration ,
11
11
} ;
12
+ use thiserror:: Error ;
12
13
use tokio:: {
13
14
signal:: unix:: { signal, SignalKind } ,
14
15
sync:: Mutex ,
@@ -217,13 +218,14 @@ enum AppResult {
217
218
Success ( ) ,
218
219
UnretryableError ( anyhow:: Error ) ,
219
220
RetryableError ( anyhow:: Error ) ,
221
+ Cancelled ( anyhow:: Error ) ,
220
222
}
221
223
222
224
impl AppResult {
223
225
fn exit_code ( & self ) -> ExitCode {
224
226
match self {
225
227
AppResult :: Success ( ) => ExitCode :: SUCCESS ,
226
- AppResult :: UnretryableError ( _) => ExitCode :: FAILURE ,
228
+ AppResult :: UnretryableError ( _) | AppResult :: Cancelled ( _ ) => ExitCode :: FAILURE ,
227
229
AppResult :: RetryableError ( _) => ExitCode :: from ( 2 ) ,
228
230
}
229
231
}
@@ -235,6 +237,7 @@ impl fmt::Display for AppResult {
235
237
AppResult :: Success ( ) => write ! ( f, "Success" ) ,
236
238
AppResult :: UnretryableError ( error) => write ! ( f, "Error(Unretryable): {error:?}" ) ,
237
239
AppResult :: RetryableError ( error) => write ! ( f, "Error(Retryable): {error:?}" ) ,
240
+ AppResult :: Cancelled ( error) => write ! ( f, "Cancelled: {error:?}" ) ,
238
241
}
239
242
}
240
243
}
@@ -259,6 +262,8 @@ impl From<StdResult<()>> for AppResult {
259
262
Err ( error) => {
260
263
if error. is :: < RetryableDevnetError > ( ) {
261
264
AppResult :: RetryableError ( error)
265
+ } else if error. is :: < SignalError > ( ) {
266
+ AppResult :: Cancelled ( error)
262
267
} else {
263
268
AppResult :: UnretryableError ( error)
264
269
}
@@ -404,32 +409,30 @@ fn create_workdir_if_not_exist_clean_otherwise(work_dir: &Path) {
404
409
fs:: create_dir ( work_dir) . expect ( "Work dir creation failure" ) ;
405
410
}
406
411
412
+ #[ derive( Error , Debug , PartialEq , Eq ) ]
413
+ #[ error( "Signal received: `{0}`" ) ]
414
+ pub struct SignalError ( pub String ) ;
415
+
407
416
fn with_gracefull_shutdown ( join_set : & mut JoinSet < StdResult < ( ) > > ) {
408
417
join_set. spawn ( async move {
409
418
let mut sigterm = signal ( SignalKind :: terminate ( ) ) . expect ( "Failed to create SIGTERM signal" ) ;
410
- sigterm
411
- . recv ( )
412
- . await
413
- . ok_or ( anyhow ! ( "Failed to receive SIGTERM" ) )
414
- . inspect ( |( ) | warn ! ( "Received SIGTERM" ) )
419
+ sigterm. recv ( ) . await ;
420
+
421
+ Err ( anyhow ! ( SignalError ( "SIGTERM" . to_string( ) ) ) )
415
422
} ) ;
416
423
417
424
join_set. spawn ( async move {
418
425
let mut sigterm = signal ( SignalKind :: interrupt ( ) ) . expect ( "Failed to create SIGINT signal" ) ;
419
- sigterm
420
- . recv ( )
421
- . await
422
- . ok_or ( anyhow ! ( "Failed to receive SIGINT" ) )
423
- . inspect ( |( ) | warn ! ( "Received SIGINT" ) )
426
+ sigterm. recv ( ) . await ;
427
+
428
+ Err ( anyhow ! ( SignalError ( "SIGINT" . to_string( ) ) ) )
424
429
} ) ;
425
430
426
431
join_set. spawn ( async move {
427
432
let mut sigterm = signal ( SignalKind :: quit ( ) ) . expect ( "Failed to create SIGQUIT signal" ) ;
428
- sigterm
429
- . recv ( )
430
- . await
431
- . ok_or ( anyhow ! ( "Failed to receive SIGQUIT" ) )
432
- . inspect ( |( ) | warn ! ( "Received SIGQUIT" ) )
433
+ sigterm. recv ( ) . await ;
434
+
435
+ Err ( anyhow ! ( SignalError ( "SIGQUIT" . to_string( ) ) ) )
433
436
} ) ;
434
437
}
435
438
@@ -441,24 +444,19 @@ mod tests {
441
444
fn app_result_exit_code ( ) {
442
445
let expected_exit_code = ExitCode :: SUCCESS ;
443
446
let exit_code = AppResult :: Success ( ) . exit_code ( ) ;
444
- assert_eq ! (
445
- format!( "{:?}" , expected_exit_code) ,
446
- format!( "{:?}" , exit_code)
447
- ) ;
447
+ assert_eq ! ( expected_exit_code, exit_code) ;
448
448
449
449
let expected_exit_code = ExitCode :: FAILURE ;
450
450
let exit_code = AppResult :: UnretryableError ( anyhow:: anyhow!( "an error" ) ) . exit_code ( ) ;
451
- assert_eq ! (
452
- format!( "{:?}" , expected_exit_code) ,
453
- format!( "{:?}" , exit_code)
454
- ) ;
451
+ assert_eq ! ( expected_exit_code, exit_code) ;
455
452
456
453
let expected_exit_code = ExitCode :: from ( 2 ) ;
457
454
let exit_code = AppResult :: RetryableError ( anyhow:: anyhow!( "an error" ) ) . exit_code ( ) ;
458
- assert_eq ! (
459
- format!( "{:?}" , expected_exit_code) ,
460
- format!( "{:?}" , exit_code)
461
- ) ;
455
+ assert_eq ! ( expected_exit_code, exit_code) ;
456
+
457
+ let expected_exit_code = ExitCode :: FAILURE ;
458
+ let exit_code = AppResult :: Cancelled ( anyhow:: anyhow!( "an error" ) ) . exit_code ( ) ;
459
+ assert_eq ! ( expected_exit_code, exit_code) ;
462
460
}
463
461
464
462
#[ test]
@@ -474,5 +472,10 @@ mod tests {
474
472
AppResult :: from( Err ( anyhow!( "an error" ) ) ) ,
475
473
AppResult :: UnretryableError ( _)
476
474
) ) ;
475
+
476
+ assert ! ( matches!(
477
+ AppResult :: from( Err ( anyhow!( SignalError ( "an error" . to_string( ) ) ) ) ) ,
478
+ AppResult :: Cancelled ( _)
479
+ ) ) ;
477
480
}
478
481
}
0 commit comments