Skip to content

fix(continuum): make auto-save die with its psmux server#30

Open
MattKotsenas wants to merge 1 commit into
psmux:mainfrom
MattKotsenas:fix/continuum-auto-save-server-lifetime
Open

fix(continuum): make auto-save die with its psmux server#30
MattKotsenas wants to merge 1 commit into
psmux:mainfrom
MattKotsenas:fix/continuum-auto-save-server-lifetime

Conversation

@MattKotsenas

@MattKotsenas MattKotsenas commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

Rewrites psmux-continuum's auto_save.ps1 so the auto-save loop lives and dies with its psmux server instead of outliving it.

Why

The old loop slept a fixed interval and only noticed the server was gone on its next wake via psmux ls, so a kill-server or restart orphaned it until the next tick. Its fixed-name mutex then blocked the new server's loop from starting until that orphan was killed (issue #24 territory).

How

  • The loop blocks on the server process itself: one WaitForExit doubles as the save cadence (its timeout) and the death signal (it returns the instant the server exits), so the loop reaps with its server.
  • The single-instance mutex is keyed to the server pid, so a new server's loop is never blocked by a dying one.
  • The server is resolved via the loop's parent process (run-shell spawns this script as a child of the server), with the process handle forced open up front to avoid a pid-reuse race.
  • Cadence is a [TimeSpan] -Interval (e.g. 00:15:00).
  • If the server dies while a save runs, the sync save finishes first (against a dead server its psmux calls return empty), then the next block reaps, so the loop outlives its server by at most one save.

Depends on

Without the psmux-side fix psmux/psmux#456, the hidden __warm__ pre-spawn server also fires client-attached and spawns a second auto-save loop (a double-save).

Testing

End-to-end against isolated psmux servers (with the #456 binary):

  • Cold-spawn session -> exactly 1 loop; saves fire on cadence; loop reaps ~150 ms after the server dies, no orphan.
  • Warm-stay (unclaimed) -> 0 loops.
  • Warm-claim (promoted) -> exactly 1 loop; reaps with its server.
  • Repeat client-attached on the same server -> mutex keeps a single loop.

The old loop slept a fixed interval and only noticed the server was gone on
its next wake via `psmux ls`, so a kill-server or restart orphaned it until
the next tick; its fixed-name mutex then blocked the new server's loop from
starting until that orphan was killed.

Block on the server instead: one WaitForExit serves as both the save cadence
(its timeout) and the death signal (it returns the instant the server exits),
so the loop reaps with its server. The single-instance mutex is now keyed to
the server pid, so a new server's loop is never blocked by a dying one.

Resolve the server via our parent process (run-shell spawns this script as a
child of the server), and force the process handle open up front to avoid a
pid-reuse race.
@psmux

psmux commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Hey @MattKotsenas, I've been going through the whole auto save cluster (#24, #26, #28) today and wanted to give this a real review rather than let it sit quiet.

I think the design here is genuinely better than what's on main. Keying the loop's lifetime to WaitForExit on the server process itself, so the same wait doubles as both the save cadence and the death signal, is a nicer invariant than polling psmux ls on a timer and hoping the exit code or output tells you something useful. Same for keying the mutex to the server pid instead of a fixed name, that directly fixes the case where a dying server's loop blocks the new server's loop from ever starting, which is real #24 territory that the fixed-name mutex in 0f46ccc doesn't address. Forcing the process handle open early to dodge the pid reuse race is the kind of detail that's easy to skip and painful to debug later, glad you thought of it.

Where things stand right now: #27 and #28 just merged (2794fc0 and 2e79d2a) as the immediate fix for the data loss in #26, the resurrect side now refuses to persist a 0-session snapshot, and the continuum loop now actually notices the server is gone via empty output and breaks, instead of running forever. That was the more urgent bug since it was actively destroying restore points, so it took priority.

I tried a merge of this branch against current main just now and it conflicts in psmux-continuum/scripts/auto_save.ps1, expected, since #28 touched the same "check if server is alive" block this PR replaces wholesale. Could you rebase onto main when you get a chance? The break-on-empty logic from #28 should mostly just go away once this lands since your pid-WaitForExit approach makes it structurally impossible to loop on a dead server in the first place, but I'd rather you make that call since you know this design best.

On the dependency: I checked, psmux/psmux#456 is merged upstream (commit 5bf1471, merged 2026-07-10). It is not in the 3.3.6 release that's currently installed here though, git merge-base --is-ancestor confirms 5bf1471 is not an ancestor of the v3.3.6 tag. So the core fix exists but hasn't shipped in a tagged release yet. Worth noting in the PR description for whoever picks this up next, since testing this properly needs a psmux build past 3.3.6, not just latest main plugins.

Keeping this open for the next iteration of the auto-save loop rather than merging now, both because of the rebase and because I'd like to E2E it (cold-spawn, warm-stay, warm-claim, repeat attach, per your own test plan) once it's on top of #28 and once there's a released core build with #456 in it. Really like where this is headed, thanks for tackling the deeper structural fix instead of just patching around the symptom.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants