

























@@ -50,6 +50,9 @@ const DEFAULT_STALE_MS = 30 * 60 * 1000;
5050const DEFAULT_MAX_HOLD_MS = 5 * 60 * 1000;
5151const DEFAULT_WATCHDOG_INTERVAL_MS = 60_000;
5252const DEFAULT_TIMEOUT_GRACE_MS = 2 * 60 * 1000;
53+// A payload-less lock can be left behind if shutdown lands between open("wx")
54+// and the owner metadata write. Keep the grace short so 10s callers recover.
55+const ORPHAN_LOCK_PAYLOAD_GRACE_MS = 5_000;
5356const MAX_LOCK_HOLD_MS = 2_147_000_000;
54575558type CleanupState = {
@@ -416,7 +419,7 @@ async function shouldReclaimContendedLockFile(
416419try {
417420const stat = await fs.stat(lockPath);
418421const ageMs = Math.max(0, nowMs - stat.mtimeMs);
419-return ageMs > staleMs;
422+return ageMs > Math.min(staleMs, ORPHAN_LOCK_PAYLOAD_GRACE_MS);
420423} catch (error) {
421424const code = (error as { code?: string } | null)?.code;
422425return code !== "ENOENT";
@@ -538,13 +541,6 @@ export async function acquireSessionWriteLock(params: {
538541let handle: fs.FileHandle | null = null;
539542try {
540543handle = await fs.open(lockPath, "wx");
541-const createdAt = new Date().toISOString();
542-const starttime = getProcessStartTime(process.pid);
543-const lockPayload: LockFilePayload = { pid: process.pid, createdAt };
544-if (starttime !== null) {
545-lockPayload.starttime = starttime;
546-}
547-await handle.writeFile(JSON.stringify(lockPayload, null, 2), "utf8");
548544const createdHeld: HeldLock = {
549545count: 1,
550546 handle,
@@ -553,13 +549,27 @@ export async function acquireSessionWriteLock(params: {
553549 maxHoldMs,
554550};
555551HELD_LOCKS.set(normalizedSessionFile, createdHeld);
552+const createdAt = new Date().toISOString();
553+const starttime = getProcessStartTime(process.pid);
554+const lockPayload: LockFilePayload = { pid: process.pid, createdAt };
555+if (starttime !== null) {
556+lockPayload.starttime = starttime;
557+}
558+await handle.writeFile(JSON.stringify(lockPayload, null, 2), "utf8");
556559return {
557560release: async () => {
558561await releaseHeldLock(normalizedSessionFile, createdHeld);
559562},
560563};
561564} catch (err) {
562565if (handle) {
566+const currentHeld = HELD_LOCKS.get(normalizedSessionFile);
567+if (currentHeld?.handle === handle) {
568+HELD_LOCKS.delete(normalizedSessionFile);
569+if (HELD_LOCKS.size === 0) {
570+stopWatchdogTimer();
571+}
572+}
563573try {
564574await handle.close();
565575} catch {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。