mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
fix(cli): server start named a pid that had already exited
Six `tty7 server start` at once reported six different pids, five of them gone by the time they were printed, and every one of them claimed `"started": true`. The singleton admits one server and the losers exit immediately — but they all spawned a child first, and they all then see `running()` go true, because the winner is up. Each reported the child it had spawned. `pid` is the field a script keeps in order to watch or stop the server, so five of six callers were handed a dead one. Report the pid that is actually serving, read from the pidfile, and say `started: false` when this call was not the one that started it — the same answer `start` already gives when a server was up before it ran. Readable by then: the daemon writes the pidfile after `bind`, and `running()` needs a request answered, which is later still. The ordinary path is untouched: a start that wins reports its own child, because that is the serving pid. Verified by racing six starts against an isolated config dir — all six now report the one live pid, exactly one says it started it — and by a single start, which reports the pid `ps` shows for that config dir. Also checked while looking for this, and sound: a truncated, garbage, empty or wrong-schema machine.json is quarantined (`.corrupt`, then `.corrupt.N`) and the server starts clean; a killed server's pane children do not leak, since closing the pty master hangs them up.
This commit is contained in:
@@ -79,9 +79,26 @@ pub fn start() -> Result<Outcome> {
|
||||
}
|
||||
std::thread::sleep(POLL_INTERVAL);
|
||||
}
|
||||
// Which pid ended up serving, which is not always the child just spawned.
|
||||
// Clients that all find no server race to start one; the singleton seat
|
||||
// admits exactly one and the losers exit immediately — but every one of
|
||||
// them then sees `running()` go true and would report its own dead child.
|
||||
// Six concurrent starts reported six different pids, five already gone,
|
||||
// and `pid` is a field scripts keep in order to watch or stop the server.
|
||||
//
|
||||
// Readable by then: the daemon writes the pidfile after `bind`, and
|
||||
// `running()` needs an answered request, which is later still.
|
||||
let serving = tty7_core::daemon::pidfile::read().unwrap_or(pid);
|
||||
let won = serving == pid;
|
||||
report(
|
||||
format!("started {} (pid {pid})", exe.display()),
|
||||
json!({ "started": true, "pid": pid, "exe": exe.display().to_string() }),
|
||||
match won {
|
||||
true => format!("started {} (pid {pid})", exe.display()),
|
||||
false => format!(
|
||||
"{} is already serving this config dir (pid {serving}) — another start won the race",
|
||||
exe.display()
|
||||
),
|
||||
},
|
||||
json!({ "started": won, "running": true, "pid": serving, "exe": exe.display().to_string() }),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user