v2.0.0: a remote app restart under the window host is the host's ladder, never a helper racing it (PC 1, 6 October 2026 19:10Z and 8 October 2026 14:50Z: the restart kind quit the engine and left a hidden PowerShell to Start-Process igneum-app.exe --launch 8 s later, racing the host's own restart ladder for the single instance; it lost both times, "the relaunch helper did not bring it back", the app down for hours with the whole job queue behind it). Now the engine decides (engine::restart_plan): under the host it sets the quit source "remote job: app restart" (a plain EXIT, so the host restarts it in about 10 s; an update exit would end the host) and starts nothing; with no host (--boot, a headless start) it starts the relaunch helper itself and keeps running when the helper cannot start. The job runner's restart arm no longer spawns the helper. Test known-failed first: engine::tests::a_remote_app_restart_under_the_host_uses_the_hosts_ladder_and_no_helper
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
1602298d08
commit
b86fcbe6b5
2 changed files with 49 additions and 9 deletions
|
|
@ -4433,7 +4433,20 @@ impl Engine {
|
|||
}
|
||||
}
|
||||
Action::RestartApp => {
|
||||
self.shared.event("info", "remote job: the app restarts (miners stop, then the node, then it opens again)");
|
||||
// v2.0.0 (PC 1, 6 and 8 October 2026): under the window host the engine exits with a plain EXIT and the
|
||||
// host's ladder starts it again in 10 s; a detached helper raced that ladder for the single instance and
|
||||
// lost twice, the app down for hours. The helper only when no host runs (--boot, a headless start).
|
||||
match restart_plan(self.wrapper) {
|
||||
RestartPlan::HostLadder => self.shared.event("info", "remote job: the app restarts (miners stop, then the node; the window opens it again in about 10 s)"),
|
||||
RestartPlan::Helper => {
|
||||
self.shared.event("info", "remote job: the app restarts (miners stop, then the node, then it opens again)");
|
||||
if let Err(e) = crate::jobrun::spawn_relaunch_helper(&self.shared) {
|
||||
self.shared.event("error", &format!("remote job: the app cannot restart by itself ({e}); it keeps running"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.quit_source = "remote job: app restart";
|
||||
self.quitting = true;
|
||||
self.st().quitting = true;
|
||||
}
|
||||
|
|
@ -5726,6 +5739,18 @@ impl Engine {
|
|||
/// the installer (PC 2, 7 October 2026, 20:54 BST: a job's silent 0.3.22 install quit the engine through api/quit, the
|
||||
/// 0.3.21 host's restart ladder started the old engine 10 s later, Inno could not replace the locked host, and every
|
||||
/// file stayed 0.3.21). A plain "EXIT" for every other quit (the tray, a crash of the node the engine gave up on).
|
||||
/// How a remote `restart --what app` brings the app back (v2.0.0). Under the window host: the engine's plain EXIT and the
|
||||
/// host's restart ladder (10 s), nothing else started. With no host: the detached relaunch helper (src/jobrun.rs).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum RestartPlan {
|
||||
HostLadder,
|
||||
Helper,
|
||||
}
|
||||
|
||||
pub fn restart_plan(under_host: bool) -> RestartPlan {
|
||||
if under_host { RestartPlan::HostLadder } else { RestartPlan::Helper }
|
||||
}
|
||||
|
||||
pub fn exit_line(quit_source: &str) -> &'static str {
|
||||
if quit_source.contains("api/quit") || quit_source.contains("installer") || quit_source.contains("update") {
|
||||
"EXIT update"
|
||||
|
|
@ -6164,6 +6189,24 @@ mod tests {
|
|||
assert_eq!(crate::ember::amd_gmax_arg(2992, 3292, true), -300);
|
||||
}
|
||||
|
||||
/// Known-failed first (PC 1, 6 and 8 October 2026: a remote app restart left the app down for hours, "the relaunch
|
||||
/// helper did not bring it back"): under the window host the restart is the host's ladder after a plain EXIT, never a
|
||||
/// helper racing it; the helper only with no host; the quit source reads as a plain EXIT, not an update exit.
|
||||
#[test]
|
||||
fn a_remote_app_restart_under_the_host_uses_the_hosts_ladder_and_no_helper() {
|
||||
assert_eq!(super::restart_plan(true), super::RestartPlan::HostLadder);
|
||||
assert_eq!(super::restart_plan(false), super::RestartPlan::Helper);
|
||||
assert_eq!(super::exit_line("remote job: app restart"), "EXIT", "a plain EXIT: the host restarts the engine (an update exit would end the host)");
|
||||
let j = include_str!("jobrun.rs");
|
||||
let arm = j.find("\"restart\" | \"update-now\" =>").unwrap();
|
||||
assert!(!j[arm..arm + 1800].contains("spawn_relaunch_helper(shared)"), "the runner no longer starts the helper itself");
|
||||
let e = include_str!("engine.rs");
|
||||
let ra = e.find("Action::RestartApp => {").unwrap();
|
||||
let body = &e[ra..ra + 1500];
|
||||
assert!(body.contains("restart_plan(self.wrapper)") && body.contains("RestartPlan::HostLadder =>") && body.contains("crate::jobrun::spawn_relaunch_helper(&self.shared)"), "the engine decides by the host");
|
||||
assert!(body.contains("self.quit_source = \"remote job: app restart\";"));
|
||||
}
|
||||
|
||||
/// PC 2, 7 October 2026, 14:39Z: "the helper did not run sequence 1 within 15 s (no line in ...helper.log)" is a FAULT line
|
||||
#[test]
|
||||
fn a_helper_that_does_not_answer_is_a_fault_line() {
|
||||
|
|
|
|||
|
|
@ -604,13 +604,10 @@ impl Jobs {
|
|||
(_, "node") => ("node restarted (the miners follow)".to_string(), Action::RestartNode),
|
||||
_ => ("app restarting".to_string(), Action::RestartApp),
|
||||
};
|
||||
if let Action::RestartApp = action {
|
||||
if let Err(e) = spawn_relaunch_helper(shared) {
|
||||
let o = Outcome { status: "failed".into(), exit: 1, summary: format!("could not start the relaunch helper: {e}"), ..Default::default() };
|
||||
self.event(shared, Event::Finished { id: job.id.clone(), outcome: o });
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// the app restart's relaunch is the ENGINE's decision (Action::RestartApp, src/engine.rs restart_plan): under the
|
||||
// window host the host's own ladder restarts the engine, and a helper here would race it for the single
|
||||
// instance (PC 1, 6 and 8 October 2026: "the relaunch helper did not bring it back", twice); the helper is
|
||||
// for an engine with no host
|
||||
let sink = Sink::new(shared, &job, &self.dir);
|
||||
sink.line(&format!("{}: {summary}", job.kind));
|
||||
let uploaded = report(shared, &job, &sink, "done", 0, now, crate::platform::unix_now(), &summary, json!({}));
|
||||
|
|
@ -2151,7 +2148,7 @@ fn run_build(shared: &Arc<Shared>, job: &Job, sink: &Sink, jobs_dir: &Path, ctl:
|
|||
// ---- kind: restart app -----------------------------------------------------------------------------------------------
|
||||
|
||||
/// A detached helper that starts the app again a few seconds after this engine has gone.
|
||||
fn spawn_relaunch_helper(shared: &Arc<Shared>) -> Result<(), String> {
|
||||
pub fn spawn_relaunch_helper(shared: &Arc<Shared>) -> Result<(), String> {
|
||||
let mut c;
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue