fix(server-s3): list a member's tmux panes asynchronously

A frozen member (SIGSTOPped tmux server) cost every user one synchronous
3 s block of the event loop per minute (F37's back-off ceiling). Member
listing now runs through async execFile (same 3 s / SIGKILL / 1 MiB
bounds, same back-off) into the listed cache the synchronous readers
(liveSessions, listSessions, listOutput) already use: stale-while-
revalidate, 15 s max age, cold or failing = that member's panes UNKNOWN
(F38 unchanged). A session this process creates or kills is written into
the member's cached answer at once, and a list in flight across that
change is dropped. Host tmux calls, local mode and every click's call
(new-session, send-keys, kill, has-session) are unchanged.

review5's stalled-member test now polls for 4 s past the timeout and
asserts each poll < 100 ms, event-loop stall < 500 ms and one sudo
(old code: first poll 3157 ms).
This commit is contained in:
2026-10-09 15:21:31 +07:00
parent 84e2a9f0ac
commit 4407b3bb16
5 changed files with 206 additions and 57 deletions
+13 -1
View File
@@ -134,12 +134,24 @@ describe("a member's panes on the member's own tmux server", () => {
assert.ok(calls.every((a) => a[0] !== "-S"));
});
it("lists sessions across every server, believing a member's only about their own", () => {
it("lists sessions across every server, believing a member's only about their own", async () => {
const orig = runAs.membersWithTmux;
runAs.membersWithTmux = () => [ACCT];
try {
// A member's list is async: until it lands their panes are UNKNOWN.
const cold = tmux.liveSessions();
assert.deepEqual([...cold].sort(), [HOST, "other"].sort());
assert.equal(cold.has(MEMBER), true, "unknown, kept");
assert.equal(cold.has("agenthub-lane-9"), false);
assert.deepEqual(tmux.listSessions("agenthub-lane-"), [HOST]);
await tmux.__settle();
assert.deepEqual([...tmux.liveSessions()].sort(), [MEMBER, HOST, "other"].sort());
assert.deepEqual(tmux.listSessions("agenthub-lane-").sort(), [HOST, MEMBER].sort());
// A session this process ends or makes is in the next answer at once.
tmux.killSession(MEMBER);
assert.deepEqual(tmux.listSessions("agenthub-lane-"), [HOST]);
tmux.newSession({ name: MEMBER, cwd: HOME, argv: ["bash"], env: {} });
assert.deepEqual(tmux.listSessions("agenthub-lane-").sort(), [HOST, MEMBER].sort());
} finally {
runAs.membersWithTmux = orig;
}