chore(gui-client): fix papercuts (#5792)

Closes #5789 

The SIGTERM catching would have helped debug #5790 

```[tasklist]
### Tasks
- [x] catch SIGTERM and log when systemd shuts us down gracefully
- [x] Log architecture at startup
```
This commit is contained in:
Reactor Scram
2024-07-08 22:20:57 +00:00
committed by GitHub
parent a054121233
commit 927702cd2f
6 changed files with 64 additions and 26 deletions

View File

@@ -158,6 +158,7 @@ fn fix_log_filter(settings: &mut AdvancedSettings) -> Result<()> {
fn start_logging(directives: &str) -> Result<logging::Handles> {
let logging_handles = logging::setup(directives)?;
tracing::info!(
arch = std::env::consts::ARCH,
?directives,
?GIT_VERSION,
system_uptime_seconds = firezone_headless_client::uptime::get().map(|dur| dur.as_secs()),

View File

@@ -91,26 +91,40 @@ pub fn run_only_ipc_service() -> Result<()> {
fn run_debug_ipc_service() -> Result<()> {
crate::setup_stdout_logging()?;
tracing::info!(
arch = std::env::consts::ARCH,
git_version = crate::GIT_VERSION,
system_uptime_seconds = crate::uptime::get().map(|dur| dur.as_secs()),
);
let rt = tokio::runtime::Runtime::new()?;
let _guard = rt.enter();
let mut signals = Signals::new()?;
// Couldn't get the loop to work here yet, so SIGHUP is not implemented
rt.block_on(async {
let ipc_service = pin!(ipc_listen());
rt.block_on(ipc_listen_with_signals(&mut signals))
}
match future::select(pin!(signals.recv()), ipc_service).await {
future::Either::Left((SignalKind::Hangup, _)) => {
bail!("Exiting, SIGHUP not implemented for the IPC service");
}
future::Either::Left((SignalKind::Interrupt, _)) => {
tracing::info!("Caught Interrupt signal");
Ok(())
}
future::Either::Right((Ok(impossible), _)) => match impossible {},
future::Either::Right((Err(error), _)) => Err(error).context("ipc_listen failed"),
/// Run the IPC service, and exit if we catch any signals
///
/// Shared between the Linux systemd service and the debug subcommand
/// TODO: Better name
async fn ipc_listen_with_signals(signals: &mut Signals) -> Result<()> {
let ipc_service = pin!(ipc_listen());
match future::select(pin!(signals.recv()), ipc_service).await {
future::Either::Left((SignalKind::Hangup, _)) => {
bail!("Exiting, SIGHUP not implemented for the IPC service");
}
})
future::Either::Left((SignalKind::Interrupt, _)) => {
tracing::info!("Caught SIGINT");
Ok(())
}
future::Either::Left((SignalKind::Terminate, _)) => {
tracing::info!("Caught SIGTERM");
Ok(())
}
future::Either::Right((Ok(impossible), _)) => match impossible {},
future::Either::Right((Err(error), _)) => Err(error).context("ipc_listen failed"),
}
}
#[cfg(not(debug_assertions))]
@@ -332,6 +346,7 @@ fn setup_logging(log_dir: Option<PathBuf>) -> Result<connlib_client_shared::file
let subscriber = Registry::default().with(layer.with_filter(filter));
set_global_default(subscriber).context("`set_global_default` should always work)")?;
tracing::info!(
arch = std::env::consts::ARCH,
git_version = crate::GIT_VERSION,
system_uptime_seconds = crate::uptime::get().map(|dur| dur.as_secs()),
?directives

View File

@@ -1,4 +1,5 @@
use super::CliCommon;
use crate::Signals;
use anyhow::{bail, Result};
/// Cross-platform entry point for systemd / Windows services
@@ -10,10 +11,10 @@ pub(crate) fn run_ipc_service(cli: CliCommon) -> Result<()> {
anyhow::bail!("This is the IPC service binary, it's not meant to run interactively.");
}
let rt = tokio::runtime::Runtime::new()?;
if let Err(error) = rt.block_on(super::ipc_listen()) {
tracing::error!(?error, "`ipc_listen` failed");
}
Ok(())
let _guard = rt.enter();
let mut signals = Signals::new()?;
rt.block_on(super::ipc_listen_with_signals(&mut signals))
}
pub(crate) fn install_ipc_service() -> Result<()> {

View File

@@ -164,6 +164,10 @@ enum SignalKind {
Hangup,
/// SIGINT
Interrupt,
/// SIGTERM
///
/// Not caught on Windows
Terminate,
}
/// Sets up logging for stdout only, with INFO level by default

View File

@@ -2,7 +2,7 @@
use super::{SignalKind, TOKEN_ENV_KEY};
use anyhow::{bail, Result};
use futures::future::{select, Either};
use futures::future::FutureExt as _;
use std::{
path::{Path, PathBuf},
pin::pin,
@@ -15,22 +15,32 @@ const ROOT_GROUP: u32 = 0;
const ROOT_USER: u32 = 0;
pub(crate) struct Signals {
/// For reloading settings in the standalone Client
sighup: Signal,
/// For Ctrl+C from a terminal
sigint: Signal,
/// For systemd service stopping
sigterm: Signal,
}
impl Signals {
pub(crate) fn new() -> Result<Self> {
let sighup = signal(TokioSignalKind::hangup())?;
let sigint = signal(TokioSignalKind::interrupt())?;
let sigterm = signal(TokioSignalKind::terminate())?;
Ok(Self { sighup, sigint })
Ok(Self {
sighup,
sigint,
sigterm,
})
}
pub(crate) async fn recv(&mut self) -> SignalKind {
match select(pin!(self.sighup.recv()), pin!(self.sigint.recv())).await {
Either::Left((_, _)) => SignalKind::Hangup,
Either::Right((_, _)) => SignalKind::Interrupt,
futures::select! {
_ = pin!(self.sighup.recv().fuse()) => SignalKind::Hangup,
_ = pin!(self.sigint.recv().fuse()) => SignalKind::Interrupt,
_ = pin!(self.sigterm.recv().fuse()) => SignalKind::Terminate,
}
}
}

View File

@@ -111,7 +111,10 @@ pub fn run_only_headless_client() -> Result<()> {
.unzip();
setup_global_subscriber(layer);
tracing::info!(git_version = crate::GIT_VERSION);
tracing::info!(
arch = std::env::consts::ARCH,
git_version = crate::GIT_VERSION
);
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
@@ -174,11 +177,15 @@ pub fn run_only_headless_client() -> Result<()> {
loop {
match future::select(pin!(signals.recv()), pin!(cb_rx.recv())).await {
future::Either::Left((SignalKind::Hangup, _)) => {
tracing::info!("Caught Hangup signal");
tracing::info!("Caught SIGHUP");
session.reconnect();
}
future::Either::Left((SignalKind::Interrupt, _)) => {
tracing::info!("Caught Interrupt signal");
tracing::info!("Caught SIGINT");
return Ok(());
}
future::Either::Left((SignalKind::Terminate, _)) => {
tracing::info!("Caught SIGTERM");
return Ok(());
}
future::Either::Right((None, _)) => {