mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-15 03:08:56 +02:00
Façade Rust, lot 3 : la supervision du moteur passe à loki-rs
En conteneur, start/stop/restart/status du moteur passent par `loki-rs engine <action>`, port à l'identique de la supervision Go : `loki serve` lancé chef de session, fichier PID et journal aux mêmes chemins (serviceIsActive, l'UI et `loki logs` lisent les mêmes fichiers), contrôle à 2 s avec la fin du journal en cas d'échec, arrêt de tout l'arbre — session, groupe et filiation, pour le moteur de Strata qui prend sa propre session — avec les mêmes délais (SIGTERM, 4 s, SIGKILL, 20 s). Le Go garde ses garde-fous (optimisation en cours, preset externe) puis délègue au loki-rs voisin de son binaire ; la dernière ligne d'erreur du superviseur devient l'erreur montrée par l'UI. LOKI_ENGINE_SUPERVISOR=go revient à l'ancienne supervision. `loki serve`, qui construit la ligne de commande du moteur, ne change pas : il aura son propre lot. Le contrôle « démarré ? » regarde si l'enfant est sorti plutôt que le signal 0 : un enfant mort reste un zombie tant que son parent vit, et un zombie répond encore au signal 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d4fa4488cc
commit
a672760f3c
9 files changed
+808
-2
No files matched your search
@@ -0,0 +1,112 @@
|
||||
//! Supervision du moteur (lot 3) — Linux seulement : /proc, setsid, signaux.
|
||||
#![cfg(target_os = "linux")]
|
||||
|
||||
use loki_rs::engine::proctree::linux::pid_alive;
|
||||
use loki_rs::engine::{self, Opts, Paths};
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Faux binaire Go : `serve` lance un « llama-server » dans sa session et un
|
||||
/// « moteur Strata » qui prend SA PROPRE session (comme le vrai), puis attend.
|
||||
fn faux_go(dir: &Path, corps: &str) -> PathBuf {
|
||||
let p = dir.join("faux-loki");
|
||||
std::fs::write(&p, format!("#!/bin/sh\n{corps}\n")).unwrap();
|
||||
std::fs::set_permissions(&p, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
p
|
||||
}
|
||||
|
||||
fn opts(go: PathBuf) -> Opts {
|
||||
Opts {
|
||||
go_bin: go,
|
||||
check_delay: Duration::from_millis(500),
|
||||
grace: Duration::from_secs(2),
|
||||
settle: Duration::from_secs(5),
|
||||
}
|
||||
}
|
||||
|
||||
fn paths(home: &Path) -> Paths {
|
||||
Paths {
|
||||
home: home.to_path_buf(),
|
||||
service: "loki-engine".into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn lire_pid(p: &Path) -> i32 {
|
||||
std::fs::read_to_string(p).unwrap().trim().parse().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn demarre_puis_arrete_tout_l_arbre() {
|
||||
let t = tempfile::tempdir().unwrap();
|
||||
let home = t.path();
|
||||
let go = faux_go(
|
||||
home,
|
||||
r#"[ "$1" = serve ] || exit 9
|
||||
echo "serve lancé dans $(pwd)"
|
||||
sleep 300 &
|
||||
echo $! > llama.pid
|
||||
setsid sleep 300 &
|
||||
echo $! > strata.pid
|
||||
wait"#,
|
||||
);
|
||||
let (p, o) = (paths(home), opts(go));
|
||||
|
||||
engine::run("start", &p, &o).unwrap();
|
||||
let chef = lire_pid(&p.pid());
|
||||
assert!(pid_alive(chef));
|
||||
std::thread::sleep(Duration::from_millis(300));
|
||||
let llama = lire_pid(&home.join("llama.pid"));
|
||||
let strata = lire_pid(&home.join("strata.pid"));
|
||||
assert!(pid_alive(llama) && pid_alive(strata));
|
||||
let log = std::fs::read_to_string(p.log()).unwrap();
|
||||
assert!(log.contains("serve lancé"), "journal : {log}");
|
||||
|
||||
// Déjà démarré : rien de relancé.
|
||||
engine::run("start", &p, &o).unwrap();
|
||||
assert_eq!(lire_pid(&p.pid()), chef);
|
||||
|
||||
engine::run("stop", &p, &o).unwrap();
|
||||
assert!(!p.pid().exists());
|
||||
for (nom, pid) in [("chef", chef), ("llama", llama), ("strata", strata)] {
|
||||
assert!(!pid_alive(pid), "{nom} (PID {pid}) survit à l'arrêt");
|
||||
}
|
||||
// Rien à arrêter : pas d'erreur.
|
||||
engine::run("stop", &p, &o).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redemarre() {
|
||||
let t = tempfile::tempdir().unwrap();
|
||||
let go = faux_go(t.path(), "exec sleep 300");
|
||||
let (p, o) = (paths(t.path()), opts(go));
|
||||
engine::run("start", &p, &o).unwrap();
|
||||
let avant = lire_pid(&p.pid());
|
||||
engine::run("restart", &p, &o).unwrap();
|
||||
let apres = lire_pid(&p.pid());
|
||||
assert_ne!(avant, apres);
|
||||
assert!(!pid_alive(avant) && pid_alive(apres));
|
||||
engine::run("stop", &p, &o).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn echec_au_demarrage() {
|
||||
let t = tempfile::tempdir().unwrap();
|
||||
let go = faux_go(t.path(), "echo 'modèle introuvable'; exit 1");
|
||||
let (p, o) = (paths(t.path()), opts(go));
|
||||
let err = engine::run("start", &p, &o).unwrap_err();
|
||||
assert_eq!(err, "service loki-engine non démarré");
|
||||
assert!(!p.pid().exists(), "PID laissé après un échec");
|
||||
assert!(
|
||||
std::fs::read_to_string(p.log())
|
||||
.unwrap()
|
||||
.contains("modèle introuvable")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn action_inconnue() {
|
||||
let t = tempfile::tempdir().unwrap();
|
||||
let (p, o) = (paths(t.path()), opts(PathBuf::from("/bin/true")));
|
||||
assert!(engine::run("enable", &p, &o).is_err());
|
||||
}
|
||||
Reference in new issue
Block a user