fix(maestro): installer unit sets KillMode=process so restarts keep sessions (NAP-330)
ci / rust (push) Successful in 5m47s
ci / rust (push) Successful in 5m47s
The generated `maestro.service` used systemd's default `KillMode=control-group`, so `systemctl restart` (any update/auto-update) SIGKILLed the daemon's whole cgroup — including the tmux server and every `maestro-<uuid>` session. recover() then found nothing, silently destroying all live sessions and their processes on every restart. Emit `KillMode=process` in the daemon unit so only the daemon's MainPID is signalled; the tmux server survives and recover() re-adopts the sessions on the next start. (The web unit spawns no tmux, so it's left unchanged.) Tests assert the daemon unit carries KillMode=process and the web unit does not. INSTALL.md notes that updating keeps sessions, and that units written before this default need a refresh. Verified live on a host: with KillMode=process a restart leaves the session's PID unchanged (recovered=1); without it, recovered=0 and the process is gone. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,11 @@ pub fn render_user_unit(exec_start: &Path) -> String {
|
||||
Type=simple\n\
|
||||
ExecStart={exec} daemon\n\
|
||||
ExecReload=/bin/kill -HUP $MAINPID\n\
|
||||
# Signal only the daemon on stop/restart, not its whole cgroup —\n\
|
||||
# otherwise systemd kills the tmux server (and every session) the\n\
|
||||
# daemon spawned, defeating tmux persistence. recover() re-adopts the\n\
|
||||
# surviving sessions on the next start (NAP-330).\n\
|
||||
KillMode=process\n\
|
||||
Restart=on-failure\n\
|
||||
RestartSec=5\n\
|
||||
\n\
|
||||
@@ -137,6 +142,28 @@ mod tests {
|
||||
assert!(body.contains("Restart=on-failure"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_sets_killmode_process_so_restart_keeps_sessions() {
|
||||
// NAP-330: without KillMode=process, `systemctl restart` SIGKILLs the
|
||||
// daemon's whole cgroup — including the tmux server and every session.
|
||||
let body = render_user_unit(Path::new("/x/maestro"));
|
||||
assert!(
|
||||
body.contains("\nKillMode=process\n"),
|
||||
"daemon unit must set KillMode=process; got:\n{body}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_unit_does_not_set_killmode() {
|
||||
// The web unit spawns no tmux, so it has no cgroup-kill problem and
|
||||
// shouldn't carry the override.
|
||||
let body = render_web_unit(Path::new("/x/maestro-web"));
|
||||
assert!(
|
||||
!body.contains("KillMode"),
|
||||
"web unit needs no KillMode; got:\n{body}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_wires_execreload_to_sighup() {
|
||||
// NAP-237: `systemctl --user reload maestro` must trigger our
|
||||
|
||||
Reference in New Issue
Block a user