fix(qmd): let only one concurrent launch start the daemon

An exclusive daemon.lock (stale after 2 minutes) is held from before the
health check until the daemon listens; a launch that loses exits 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Julian lechnerandClaude Opus 5.5 committed 2026-10-08 12:47:03 +02:00
1 parent 691ad6a69f
commit 3012e1666e
2 files changed
+47 -5

No files matched your search

+16 -2
View File
@@ -2,10 +2,10 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { execFileSync } from 'node:child_process';
import { mkdtempSync, rmSync, utimesSync, writeFileSync } from 'node:fs';
import { existsSync, mkdtempSync, rmSync, utimesSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { createServer, gitFingerprint, ignoreGlobs, keepModelsLoaded } from '../../shared/qmd/qmd-daemon.mjs';
import { acquireStartLock, createServer, gitFingerprint, ignoreGlobs, keepModelsLoaded } from '../../shared/qmd/qmd-daemon.mjs';
import { collectionName } from '../../shared/qmd/qmd-lib.mjs';
const defaultHits = () => [{ displayPath: `${collectionName('/r')}/src/a.ts`, body: 'x\nretry here', bestChunkPos: 2, bestChunk: 'retry here', score: 0.91 }];
@@ -201,3 +201,17 @@ test('git ignored paths reach addCollection and are persisted only when they cha
assert.deepEqual(persisted[1], [collectionName('/r'), ['dist/**', 'tmp/**']]);
assert.equal(s.store.calls.filter((c) => c[0] === 'update').length, 3);
});
test('the start lock admits one launcher and is taken over after 2 minutes', (t) => {
const dir = mkdtempSync(join(tmpdir(), 'qmd-lock-'));
t.after(() => rmSync(dir, { recursive: true, force: true }));
const lock = join(dir, 'daemon.lock');
const release = acquireStartLock(lock);
assert.equal(typeof release, 'function');
assert.equal(acquireStartLock(lock), null, 'a concurrent launch loses');
release();
assert.equal(existsSync(lock), false);
assert.equal(typeof acquireStartLock(lock), 'function');
assert.equal(acquireStartLock(lock, () => Date.now() + 60_000), null, 'a fresh lock holds');
assert.equal(typeof acquireStartLock(lock, () => Date.now() + 121_000), 'function', 'a stale lock is taken over');
});