fix: clear stale health notifications

This commit is contained in:
Dorian
2026-05-14 08:57:54 -04:00
parent f95e9a1cd0
commit b8053c00ca
3 changed files with 38 additions and 5 deletions

View File

@@ -65,7 +65,9 @@ pub async fn ensure_doctor_installed() {
Err(e) => warn!("Nginx bootstrap failed (non-fatal): {:#}", e),
}
match run_bitcoin_rpc_repair().await {
Ok(true) => info!("Repaired Bitcoin RPC bind settings; running Bitcoin containers left untouched"),
Ok(true) => {
info!("Repaired Bitcoin RPC bind settings; running Bitcoin containers left untouched")
}
Ok(false) => debug!("Bitcoin RPC bind settings already usable"),
Err(e) => warn!("Bitcoin RPC repair failed (non-fatal): {:#}", e),
}

View File

@@ -298,7 +298,11 @@ fn shell_join(parts: &[String]) -> String {
fn quote_environment(env: &str) -> String {
let env = env.replace(['\r', '\n'], " ");
if env.is_empty() || env.chars().any(|c| c.is_whitespace() || "\"\\$`".contains(c)) {
if env.is_empty()
|| env
.chars()
.any(|c| c.is_whitespace() || "\"\\$`".contains(c))
{
let escaped = env
.replace('\\', "\\\\")
.replace('"', "\\\"")
@@ -793,7 +797,10 @@ mod tests {
#[test]
fn quote_environment_quotes_values_with_spaces() {
assert_eq!(quote_environment("BITCOIN_RPC_PASS=secret"), "BITCOIN_RPC_PASS=secret");
assert_eq!(
quote_environment("BITCOIN_RPC_PASS=secret"),
"BITCOIN_RPC_PASS=secret"
);
assert_eq!(
quote_environment("RELAY_NAME=Archipelago Nostr Relay"),
"\"RELAY_NAME=Archipelago Nostr Relay\""

View File

@@ -514,7 +514,14 @@ async fn cleanup_stale_podman_healthcheck_units(live_container_ids: &HashSet<Str
async fn stale_healthcheck_units_from_systemd(live_container_ids: &HashSet<String>) -> Vec<String> {
let mut units = Vec::new();
for args in [
["--user", "list-timers", "--all", "--no-legend", "--no-pager"].as_slice(),
[
"--user",
"list-timers",
"--all",
"--no-legend",
"--no-pager",
]
.as_slice(),
["--user", "list-units", "--all", "--no-legend", "--no-pager"].as_slice(),
] {
let output = match tokio::time::timeout(
@@ -833,6 +840,21 @@ pub fn spawn_health_monitor(state: Arc<StateManager>, data_dir: PathBuf) {
}
}
let unhealthy_app_ids: HashSet<&str> = unhealthy
.iter()
.map(|container| container.app_id.as_str())
.collect();
let before = data.notifications.len();
data.notifications.retain(|n| {
!n.id.starts_with("health-")
|| n.app_id
.as_deref()
.is_some_and(|app_id| unhealthy_app_ids.contains(app_id))
});
if data.notifications.len() != before {
state_changed = true;
}
// Sort by startup tier: databases first, then core, then dependent, then apps, then UIs
unhealthy.sort_by_key(|c| container_tier(&c.name));
@@ -1346,7 +1368,9 @@ mod tests {
);
assert_eq!(parse_podman_healthcheck_unit("grafana.service"), None);
assert_eq!(
parse_podman_healthcheck_unit("nothexzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz-x.timer"),
parse_podman_healthcheck_unit(
"nothexzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz-x.timer"
),
None
);
}