fix(tmux): bound calls on our own server and run them with the server's own binary
A tmux 3.8 installed under a running 3.6 server left PATH's 3.8 client asking the 3.6 server, which spun at 100% CPU; the dashboard's synchronous `has-session` on it had no limit and froze every page, hook and terminal for five minutes (14:07–14:12 on the shared server). - Every call on our own server now has a 5 s limit and the member's one-minute back-off (`host: tmux server not answering` meanwhile), so a stuck server costs the event loop one timeout per minute, not one per poll. - Every call on a running server runs that server's own binary (`/proc/<pid>/exe`, found from its listening socket in /proc — asking tmux would be the very call that hangs), re-read every 10 s; PATH's tmux only starts a server or answers `-V`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -344,3 +344,56 @@ describe("tmux wrapper", () => {
|
||||
assert.equal(tmux.upgradeAdvice("3.3.2", "freebsd"), null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("our own tmux server: bounded and version-matched", () => {
|
||||
const fs = require("node:fs");
|
||||
const os = require("node:os");
|
||||
const path = require("node:path");
|
||||
|
||||
beforeEach(() => tmux.__reset());
|
||||
|
||||
it("backs off after a call to our server times out, instead of blocking every poll", () => {
|
||||
let calls = 0;
|
||||
tmux.__setExecImpl(() => {
|
||||
calls++;
|
||||
throw Object.assign(new Error("spawnSync tmux ETIMEDOUT"), { code: "ETIMEDOUT" });
|
||||
});
|
||||
assert.equal(tmux.hasSession("agenthub-lane-1"), false);
|
||||
const after = calls;
|
||||
assert.ok(after >= 1);
|
||||
// Meanwhile nothing reaches tmux: the server is left alone for a minute.
|
||||
assert.equal(tmux.hasSession("agenthub-lane-1"), false);
|
||||
assert.equal(tmux.serverPid(), null);
|
||||
assert.equal(calls, after);
|
||||
});
|
||||
|
||||
it("finds the binary of the server listening on our socket from /proc alone", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "tmux-proc-"));
|
||||
const sock = "/tmp/tmux-1000/default";
|
||||
fs.mkdirSync(path.join(root, "net"));
|
||||
fs.writeFileSync(
|
||||
path.join(root, "net", "unix"),
|
||||
"Num RefCount Protocol Flags Type St Inode Path\n" +
|
||||
`0000: 00000003 00000000 00000000 0001 03 777 ${sock}\n` + // a client's
|
||||
`0000: 00000002 00000000 00010000 0001 01 4242 ${sock}\n` // the listener
|
||||
);
|
||||
const proc = (pid, comm, fds) => {
|
||||
fs.mkdirSync(path.join(root, pid, "fd"), { recursive: true });
|
||||
fs.writeFileSync(path.join(root, pid, "comm"), `${comm}\n`);
|
||||
fs.symlinkSync(process.execPath, path.join(root, pid, "exe"));
|
||||
fds.forEach((t, i) => fs.symlinkSync(t, path.join(root, pid, "fd", String(i))));
|
||||
};
|
||||
proc("10", "bash", ["socket:[4242]"]); // not tmux
|
||||
proc("11", "tmux: client", ["socket:[777]"]);
|
||||
proc("12", "tmux: server", ["/dev/null", "socket:[4242]"]);
|
||||
try {
|
||||
assert.equal(
|
||||
tmux.serverExeFor(sock, { procRoot: root, uid: null }),
|
||||
path.join(root, "12", "exe")
|
||||
);
|
||||
assert.equal(tmux.serverExeFor("/tmp/other", { procRoot: root, uid: null }), null);
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user