()
| 430 | |
| 431 | #[tokio::main(flavor = "current_thread")] |
| 432 | async fn main() -> hyperqueue::Result<()> { |
| 433 | // Augment panics - first print the error and backtrace like normally, |
| 434 | // and then print our own custom error message. |
| 435 | let std_panic = std::panic::take_hook(); |
| 436 | std::panic::set_hook(Box::new(move |info: &PanicHookInfo| { |
| 437 | std_panic(info); |
| 438 | hq_panic_hook(info); |
| 439 | })); |
| 440 | |
| 441 | // Also enable backtraces by default. |
| 442 | // This enables backtraces when panicking, but also for normal anyhow errors. |
| 443 | // SAFETY: we are at the beginning of the program, no other threads that could set |
| 444 | // environment variables should be executing. |
| 445 | unsafe { |
| 446 | std::env::set_var("RUST_BACKTRACE", "full"); |
| 447 | } |
| 448 | |
| 449 | // This further disables backtraces for normal anyhow errors. |
| 450 | // They should not be printed to users in release mode. |
| 451 | #[cfg(not(debug_assertions))] |
| 452 | { |
| 453 | unsafe { |
| 454 | std::env::set_var("RUST_LIB_BACKTRACE", "0"); |
| 455 | } |
| 456 | } |
| 457 | |
| 458 | let matches = RootOptions::command().get_matches(); |
| 459 | let top_opts = match RootOptions::from_arg_matches(&matches) { |
| 460 | Ok(opts) => opts, |
| 461 | Err(error) => error.exit(), |
| 462 | }; |
| 463 | |
| 464 | setup_logging(top_opts.common.debug); |
| 465 | |
| 466 | let gsettings = make_global_settings(top_opts.common); |
| 467 | |
| 468 | let is_cli_like = match &top_opts.subcmd { |
| 469 | SubCommand::Server(ServerOpts { |
| 470 | subcmd: ServerCommand::Start(_), |
| 471 | }) => false, |
| 472 | SubCommand::Worker(WorkerOpts { |
| 473 | subcmd: WorkerCommand::Start(_), |
| 474 | }) => false, |
| 475 | #[cfg(feature = "dashboard")] |
| 476 | SubCommand::Dashboard(_) => false, |
| 477 | _ => true, |
| 478 | }; |
| 479 | |
| 480 | if is_cli_like { |
| 481 | // When our stdout is attached to a pipe and the pipe is closed, |
| 482 | // it manifests as an I/O error, because the Rust runtime ignores |
| 483 | // SIGPIPE by default. |
| 484 | // This in turn causes `println!` to panic, which is not ideal, |
| 485 | // because it crashes HQ when used with Unix CLI utilities (such as `head`). |
| 486 | // Therefore, we reset SIGPIPE to its default behavior (terminate the process) |
| 487 | // to avoid the panics. |
| 488 | // See https://github.com/It4innovations/hyperqueue/issues/851. |
| 489 | // However, we only do this for client commands, which are short running and |
nothing calls this directly
no test coverage detected