mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-12 11:40:51 +01:00
fix: gstack-skill-end releases its run on the workflow lease, so a finished /ship stops blocking gstack-upgrade (GST-1205)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
c197a139b7
commit
03ada799e8
8 files changed
+100
-22
No files matched your search
@@ -91,7 +91,7 @@ describe('gstack-lease', () => {
|
||||
const r = spawnSync('bash', ['-n', LEASE], { encoding: 'utf8', timeout: 30_000 });
|
||||
expect(r.status, r.stderr).toBe(0);
|
||||
const help = spawnSync('bash', [LEASE, '--help'], { encoding: 'utf8', timeout: 30_000 });
|
||||
expect(help.stdout).toContain('print `<pid> <age>m alive|dead|stale` for every lease');
|
||||
expect(help.stdout).toContain('print `<pid> <age>m alive|idle|dead|stale` for every lease');
|
||||
});
|
||||
|
||||
test('touch writes <git dir>/gstack-leases/<pid> for --pid and prunes leases older than 120 minutes', () => {
|
||||
@@ -716,6 +716,30 @@ describe('gstack-lease', () => {
|
||||
}
|
||||
});
|
||||
|
||||
// GST-1205: gstack-skill-end releases the run gstack-skill-start opened, so a finished run stops holding the lease.
|
||||
test('gstack-skill-start opens a run on the lease and gstack-skill-end with its SESSION_ID releases it; another holder still counts', () => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-lease-home-'));
|
||||
const state = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-lease-state-'));
|
||||
dirs.push(home, state);
|
||||
fs.writeFileSync(path.join(state, 'config.yaml'), 'update_check: false\n');
|
||||
const leaseDir = path.join(state, 'leases');
|
||||
const env = { PATH: process.env.PATH!, HOME: home, GSTACK_HOME: state, GSTACK_LEASE_DIR: leaseDir };
|
||||
const holder = sleeper();
|
||||
const start = spawnSync(START, ['--skill', 'ship', '--parent-pid', String(holder)], { encoding: 'utf8', cwd: home, env, timeout: 30_000 });
|
||||
expect(start.status, start.stdout + start.stderr).toBe(0);
|
||||
const sid = start.stdout.match(/^SESSION_ID: (\S+)$/m)?.[1] ?? '';
|
||||
expect(sid.startsWith(`${holder}-`), sid).toBe(true);
|
||||
expect(run(['live'], env).status).toBe(0);
|
||||
const end = spawnSync(path.join(REPO, 'bin/gstack-skill-end'), ['--skill', 'ship', '--outcome', 'success', '--session-id', sid, '--tel-start', '0'], { encoding: 'utf8', cwd: home, env, timeout: 30_000 });
|
||||
expect(end.status, end.stdout + end.stderr).toBe(0);
|
||||
const after = run(['live'], env);
|
||||
expect(after.status, after.stdout + after.stderr).toBe(1);
|
||||
expect(run(['list'], env).stdout).toMatch(new RegExp(`^${holder} \\d+m idle$`, 'm'));
|
||||
const other = sleeper();
|
||||
expect(run(['touch', '--pid', String(other)], env).status).toBe(0);
|
||||
expect(run(['live'], env).stdout).toMatch(new RegExp(`^${other} \\d+m sleep$`, 'm'));
|
||||
});
|
||||
|
||||
test('gstack-skill-start reports a lease the held lock kept from being written, and still starts', () => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-lease-home-'));
|
||||
const state = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-lease-state-'));
|
||||
|
||||
@@ -216,14 +216,14 @@ describe('gstack-upgrade', () => {
|
||||
// every session's lease names capy-server and the caller's own-ancestry
|
||||
// exclusion used to drop a sibling's fresh lease: a hand-run upgrade moved the checkout.
|
||||
describe('a lease held by a shared harness (capy-server) ancestor', () => {
|
||||
const underHarness = (f: ReturnType<typeof fixture>, harness: string, ageMinutes: number, extra: Record<string, string> = {}) => {
|
||||
const underHarness = (f: ReturnType<typeof fixture>, harness: string, ageMinutes: number, extra: Record<string, string> = {}, lease = 'bash "$1" touch --root "$2" --pid $$ || exit 9') => {
|
||||
const bin = path.join(f.host.base, 'harness');
|
||||
fs.mkdirSync(bin, { recursive: true });
|
||||
const exe = path.join(bin, harness);
|
||||
if (!fs.existsSync(exe)) fs.copyFileSync(fs.realpathSync(spawnSync('bash', ['-c', 'command -v bash'], { encoding: 'utf8', timeout: 30_000 }).stdout.trim()), exe);
|
||||
fs.chmodSync(exe, 0o755);
|
||||
const script = [
|
||||
'bash "$1" touch --root "$2" --pid $$ || exit 9',
|
||||
lease,
|
||||
'[ "$4" -gt 0 ] && "$5" -e "const t = Date.now() / 1000 - Number(process.argv[2]) * 60; require(\'fs\').utimesSync(process.argv[1], t, t)" "${GSTACK_LEASE_DIR:-$(git -C "$2" rev-parse --absolute-git-dir)/gstack-leases}/$$" "$4"',
|
||||
'bash "$3"',
|
||||
'echo "exit=$?"',
|
||||
@@ -242,6 +242,21 @@ describe('gstack-upgrade', () => {
|
||||
expect(f.git(['rev-parse', 'HEAD'])).toBe(f.b);
|
||||
});
|
||||
|
||||
// GST-1205: a finished /ship run's lease used to block the upgrade for 120 minutes.
|
||||
test('a lease whose runs all finished (gstack-lease release) no longer blocks; a sibling run still open on the same harness does', () => {
|
||||
const touch = (id: string) => `bash "$1" touch --root "$2" --pid $$ --run "$$-${id}"`;
|
||||
const release = (id: string) => `bash "$1" release --root "$2" --pid $$ --run "$$-${id}"`;
|
||||
const f = fixture();
|
||||
const open = underHarness(f, 'capy-server', 0, {}, `${touch('1-a')} && ${touch('2-b')} && ${release('1-a')} || exit 9`);
|
||||
expect(open.stdout, open.stdout + open.stderr).toContain('exit=3');
|
||||
expect(open.stderr).toContain('(UPGRADE_BUSY)');
|
||||
expect(f.git(['rev-parse', 'HEAD'])).toBe(f.a);
|
||||
const finished = underHarness(f, 'capy-server', 0, {}, `${touch('1-a')} && ${release('1-a')} || exit 9`);
|
||||
expect(finished.stdout, finished.stdout + finished.stderr).toContain('exit=0');
|
||||
expect(finished.stderr).not.toContain('UPGRADE_BUSY');
|
||||
expect(f.git(['rev-parse', 'HEAD'])).toBe(f.b);
|
||||
});
|
||||
|
||||
test('once that lease is 120 minutes old the upgrade proceeds', () => {
|
||||
const f = fixture();
|
||||
const r = underHarness(f, 'capy-server', 121);
|
||||
|
||||
Reference in new issue
Block a user