lifecycle: leak the stop-failed warning kind once per agent
Closes #6096
This commit is contained in:
parent
18e4f195e5
commit
32af7e0639
2 changed files with 39 additions and 6 deletions
|
|
@ -325,11 +325,20 @@ fn stop_failed_guards()
|
||||||
REG.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
|
REG.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Leak a per-agent warning `kind`. Agent names are a small, bounded set —
|
/// The per-agent warning `kind`, leaked on the first call for a name and
|
||||||
/// leaking one short string per distinct agent that ever hits a stop
|
/// returned unchanged afterwards, whether or not the warning was cleared in
|
||||||
/// failure is cheap.
|
/// between. The leak is one short string per distinct agent name.
|
||||||
fn static_stop_kind(name: &str) -> &'static str {
|
fn stop_kind(name: &str) -> &'static str {
|
||||||
Box::leak(format!("agent_stop_failed_{name}").into_boxed_str())
|
static KINDS: std::sync::OnceLock<
|
||||||
|
std::sync::Mutex<std::collections::HashMap<String, &'static str>>,
|
||||||
|
> = std::sync::OnceLock::new();
|
||||||
|
let mut kinds = KINDS
|
||||||
|
.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
|
||||||
|
.lock()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
|
kinds
|
||||||
|
.entry(name.to_owned())
|
||||||
|
.or_insert_with(|| Box::leak(format!("agent_stop_failed_{name}").into_boxed_str()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop `name`'s container. See `hive-priv`'s `stop_and_release` for why
|
/// Stop `name`'s container. See `hive-priv`'s `stop_and_release` for why
|
||||||
|
|
@ -356,7 +365,7 @@ pub async fn kill(name: &str) -> Result<()> {
|
||||||
guards.insert(
|
guards.insert(
|
||||||
name.to_owned(),
|
name.to_owned(),
|
||||||
crate::warnings::set_warning(
|
crate::warnings::set_warning(
|
||||||
static_stop_kind(name),
|
stop_kind(name),
|
||||||
"crit",
|
"crit",
|
||||||
format!("{name}: stop failed — {e}"),
|
format!("{name}: stop failed — {e}"),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -422,3 +422,27 @@ fn a_build_without_a_log_row_has_an_empty_build_id() {
|
||||||
assert_eq!(field(&logged[0].1, "build_id"), Some(""));
|
assert_eq!(field(&logged[0].1, "build_id"), Some(""));
|
||||||
assert_eq!(field(&logged[0].1, "agent"), Some("alice"));
|
assert_eq!(field(&logged[0].1, "agent"), Some("alice"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stop_kind_is_leaked_once_per_agent() {
|
||||||
|
let first = stop_kind("stopkind-a");
|
||||||
|
assert_eq!(first, "agent_stop_failed_stopkind-a");
|
||||||
|
assert!(std::ptr::eq(first, stop_kind("stopkind-a")));
|
||||||
|
assert!(!std::ptr::eq(first, stop_kind("stopkind-b")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stop_kind_survives_a_clean_stop_between_failures() {
|
||||||
|
let failed = |guards: &mut std::collections::HashMap<_, _>| {
|
||||||
|
let kind = stop_kind("stopkind-c");
|
||||||
|
guards.insert(
|
||||||
|
"stopkind-c".to_owned(),
|
||||||
|
crate::warnings::set_warning(kind, "crit", "stop failed"),
|
||||||
|
);
|
||||||
|
kind
|
||||||
|
};
|
||||||
|
let mut guards = std::collections::HashMap::new();
|
||||||
|
let first = failed(&mut guards);
|
||||||
|
guards.remove("stopkind-c");
|
||||||
|
assert!(std::ptr::eq(first, failed(&mut guards)));
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue