fix: report a gate-lease wait only when the run actually queued (#2369)

acquireLease now returns how long it spent looping behind a holder, and 0
when its first attempt succeeded however long that attempt took. The
"acquired after" line and the "(waited … first)" suffix key off that, so
an uncontended run whose lock call is slow on a loaded machine no longer
claims to have waited, and the "two concurrent runs serialize" test's
count is deterministic under load.

runUnderLease gains an injectable base `fs`, which the new regression
test uses to make an uncontended lock call outlast several polls.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wBGpf72yP3dJvcz8Y2PbL
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-09-14 08:39:56 -04:00
commit d76a67f874

View file

@ -8,6 +8,7 @@
import { after, test } from "node:test";
import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import nodeFs from "node:fs";
import {
existsSync,
mkdirSync,
@ -231,6 +232,28 @@ test("two concurrent runs serialize: the second starts after the first ends", as
assert.ok(!existsSync(leaseTarget(dir)), "the holder record goes with it");
});
test("an uncontended run whose lock call is slow does not report a wait (#2369)", async () => {
const dir = freshDir();
const { lines, log } = collectLog();
const pollMs = 25;
// A loaded machine, made deterministic: the lock directory's creation
// alone outlasts several polls, though nobody else holds the lease.
const slowFs = {
...nodeFs,
mkdir: (p, cb) => setTimeout(() => nodeFs.mkdir(p, cb), pollMs * 4),
};
assert.equal(await runNode("", { dir, log, pollMs, fs: slowFs }), 0);
assert.deepEqual(
lines.filter((l) => l.startsWith("gate-lease: acquired after")),
[],
);
const released = lines.filter((l) =>
l.startsWith("gate-lease: released after"),
);
assert.equal(released.length, 1);
assert.doesNotMatch(released[0], /waited/);
});
test("the child's exit code is the run's exit code", async () => {
const dir = freshDir();
assert.equal(await runNode("process.exit(7)", { dir, log: () => {} }), 7);