log the queue-connect and identity-mint failures the alert rules match
hh-swarm-queue-connect-failed matched "swarm queue connect failed; this
agent publishes nothing upward", which nothing has logged since the
harness started retrying its first connect and exiting (235bc481b). The
rule now matches the error the harness logs when every attempt has
failed, CONNECT_EXHAUSTED in swarm_queue.rs, and its comment and summary
describe the retry-then-exit behaviour.
A failed MintAgentIdentity node logged nothing: the error reached only
the job graph. mint_identity now warns with the agent and the error, and
hh-agent-identity-mint-failed fires on that line.
Refs #4651
This commit is contained in:
parent
0599c132e5
commit
9258563f9c
6 changed files with 166 additions and 14 deletions
|
|
@ -45,6 +45,13 @@ const CONNECT_BACKOFF: [Duration; 6] = [
|
|||
Duration::from_secs(160),
|
||||
];
|
||||
|
||||
/// Logged at `error` once every first-connect attempt has failed, just before
|
||||
/// the process exits. The Grafana rule `hh-swarm-queue-connect-failed`
|
||||
/// (`nix/host-modules/swarm-grafana.nix`) matches this exact text: change both
|
||||
/// together.
|
||||
const CONNECT_EXHAUSTED: &str =
|
||||
"no swarm queue connection; exiting, since this agent cannot run without one";
|
||||
|
||||
/// Where to connect, resolved once at boot by [`init`].
|
||||
static AGENT: OnceLock<AgentPath> = OnceLock::new();
|
||||
|
||||
|
|
@ -300,14 +307,15 @@ async fn connect_or_exit() -> async_nats::Client {
|
|||
None => Err(anyhow!("swarm_queue::init has not run")),
|
||||
};
|
||||
connected.unwrap_or_else(|e| {
|
||||
tracing::error!(
|
||||
error = format!("{e:#}"),
|
||||
"no swarm queue connection; exiting, since this agent cannot run without one"
|
||||
);
|
||||
log_connect_exhausted(&e);
|
||||
std::process::exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
fn log_connect_exhausted(e: &anyhow::Error) {
|
||||
tracing::error!(error = format!("{e:#}"), "{CONNECT_EXHAUSTED}");
|
||||
}
|
||||
|
||||
/// One connection attempt with this agent's own credential.
|
||||
async fn connect_once(agent: &AgentPath) -> anyhow::Result<async_nats::Client> {
|
||||
let secret = AgentSecret::new(Arc::clone(&agent.store));
|
||||
|
|
@ -390,10 +398,11 @@ mod tests {
|
|||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use tracing_subscriber::layer::SubscriberExt as _;
|
||||
|
||||
use super::{
|
||||
AgentPath, AgentSecret, CONNECT_BACKOFF, SecretSource, StoreSource, agent_path,
|
||||
connect_as_agent, retry_first_connect, store_source,
|
||||
connect_as_agent, log_connect_exhausted, retry_first_connect, store_source,
|
||||
};
|
||||
|
||||
/// A lookup standing in for a container that was handed a store and the
|
||||
|
|
@ -546,6 +555,50 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
/// The level and message of every event.
|
||||
#[derive(Clone, Default)]
|
||||
struct Messages(Arc<Mutex<Vec<(tracing::Level, String)>>>);
|
||||
|
||||
impl<S: tracing::Subscriber> tracing_subscriber::Layer<S> for Messages {
|
||||
fn on_event(
|
||||
&self,
|
||||
event: &tracing::Event<'_>,
|
||||
_: tracing_subscriber::layer::Context<'_, S>,
|
||||
) {
|
||||
let mut message = String::new();
|
||||
event.record(
|
||||
&mut |field: &tracing::field::Field, value: &dyn std::fmt::Debug| {
|
||||
if field.name() == "message" {
|
||||
message = format!("{value:?}");
|
||||
}
|
||||
},
|
||||
);
|
||||
self.0
|
||||
.lock()
|
||||
.expect("unpoisoned")
|
||||
.push((*event.metadata().level(), message));
|
||||
}
|
||||
}
|
||||
|
||||
/// The literal is the `_msg` that `hh-swarm-queue-connect-failed` in
|
||||
/// `nix/host-modules/swarm-grafana.nix` matches.
|
||||
#[test]
|
||||
fn an_exhausted_connect_logs_the_line_the_alert_rule_matches() {
|
||||
let messages = Messages::default();
|
||||
let subscriber = tracing_subscriber::registry().with(messages.clone());
|
||||
tracing::subscriber::with_default(subscriber, || {
|
||||
log_connect_exhausted(&anyhow!("7 connection attempts failed"));
|
||||
});
|
||||
assert_eq!(
|
||||
*messages.0.lock().expect("unpoisoned"),
|
||||
[(
|
||||
tracing::Level::ERROR,
|
||||
"no swarm queue connection; exiting, since this agent cannot run without one"
|
||||
.to_owned()
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
enum Answer {
|
||||
Value(&'static str),
|
||||
Absent,
|
||||
|
|
|
|||
Loading…
Reference in a new issue