MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / acquireLock

Function acquireLock

src/utils/file-lock.ts:35–72  ·  view source on GitHub ↗
(lockPath: string, opts: LockOptions = {})

Source from the content-addressed store, hash-verified

33 * can't be acquired within the retry budget.
34 */
35export async function acquireLock(lockPath: string, opts: LockOptions = {}): Promise<LockHandle> {
36 const retries = opts.retries ?? 50;
37 const intervalMs = opts.intervalMs ?? 100;
38 const staleMs = opts.staleMs ?? 30_000;
39
40 for (let attempt = 0; attempt <= retries; attempt++) {
41 try {
42 const fh = await fs.open(lockPath, 'wx'); // O_CREAT|O_EXCL → fails if held
43 try {
44 await fh.writeFile(`${process.pid} ${new Date().toISOString()}`);
45 } finally {
46 await fh.close();
47 }
48 let released = false;
49 return {
50 release: async () => {
51 if (released) return;
52 released = true;
53 await fs.unlink(lockPath).catch(() => {});
54 },
55 };
56 } catch (err: any) {
57 if (err?.code !== 'EEXIST') throw err;
58 // Held by someone else — reclaim if stale, else wait and retry.
59 try {
60 const st = await fs.stat(lockPath);
61 if (Date.now() - st.mtimeMs > staleMs) {
62 await fs.unlink(lockPath).catch(() => {});
63 continue; // retry immediately after reclaiming a stale lock
64 }
65 } catch {
66 /* lock vanished between open and stat — just retry */
67 }
68 if (attempt < retries) await sleep(intervalMs);
69 }
70 }
71 throw new Error(`Could not acquire lock ${lockPath} after ${retries} retries (held by another process?)`);
72}
73
74/** Run `fn` while holding `lockPath`; always releases, even on throw. */
75export async function withLock<T>(lockPath: string, fn: () => Promise<T>, opts?: LockOptions): Promise<T> {

Callers 3

withLockFunction · 0.85
beginMethod · 0.85

Calls 1

sleepFunction · 0.70

Tested by

no test coverage detected