mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-29 10:02:04 +00:00
fix: avoid fd warnings in lock exit cleanup
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import fsSync from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
@@ -228,17 +227,14 @@ describe("acquireSessionWriteLock", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("closes file descriptors synchronously during process-exit cleanup", async () => {
|
||||
it("removes lock files during process-exit cleanup", async () => {
|
||||
await withTempSessionLockFile(async ({ sessionFile, lockPath }) => {
|
||||
const closeSyncSpy = vi.spyOn(fsSync, "closeSync");
|
||||
const lock = await acquireSessionWriteLock({ sessionFile, timeoutMs: 500 });
|
||||
|
||||
__testing.releaseAllLocksSync();
|
||||
|
||||
expect(closeSyncSpy).toHaveBeenCalledTimes(1);
|
||||
await expect(fs.access(lockPath)).rejects.toThrow();
|
||||
await lock.release();
|
||||
closeSyncSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -63,27 +63,6 @@ type LockInspectionDetails = Pick<
|
||||
"pid" | "pidAlive" | "createdAt" | "ageMs" | "stale" | "staleReasons"
|
||||
>;
|
||||
|
||||
function markFileHandleClosedSync(handle: fs.FileHandle): void {
|
||||
const mutableHandle = handle as unknown as Record<PropertyKey, unknown>;
|
||||
for (const key of Reflect.ownKeys(handle)) {
|
||||
if (typeof key !== "symbol") {
|
||||
continue;
|
||||
}
|
||||
const name = String(key);
|
||||
if (name === "Symbol(kFd)") {
|
||||
mutableHandle[key] = -1;
|
||||
continue;
|
||||
}
|
||||
if (name === "Symbol(kRefs)") {
|
||||
mutableHandle[key] = 0;
|
||||
continue;
|
||||
}
|
||||
if (name === "Symbol(kClosePromise)") {
|
||||
mutableHandle[key] = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const HELD_LOCKS = resolveProcessScopedMap<HeldLock>(HELD_LOCKS_KEY);
|
||||
|
||||
function resolveCleanupState(): CleanupState {
|
||||
@@ -198,14 +177,6 @@ async function releaseHeldLock(
|
||||
*/
|
||||
function releaseAllLocksSync(): void {
|
||||
for (const [sessionFile, held] of HELD_LOCKS) {
|
||||
try {
|
||||
if (typeof held.handle.fd === "number" && held.handle.fd >= 0) {
|
||||
fsSync.closeSync(held.handle.fd);
|
||||
markFileHandleClosedSync(held.handle);
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors during cleanup - best effort
|
||||
}
|
||||
try {
|
||||
fsSync.rmSync(held.lockPath, { force: true });
|
||||
} catch {
|
||||
|
||||
@@ -30,43 +30,21 @@ const HELD_LOCKS_KEY = Symbol.for("openclaw.fileLockHeldLocks");
|
||||
const HELD_LOCKS = resolveProcessScopedMap<HeldLock>(HELD_LOCKS_KEY);
|
||||
const CLEANUP_REGISTERED_KEY = Symbol.for("openclaw.fileLockCleanupRegistered");
|
||||
|
||||
function markFileHandleClosedSync(handle: fs.FileHandle): void {
|
||||
const mutableHandle = handle as unknown as Record<PropertyKey, unknown>;
|
||||
for (const key of Reflect.ownKeys(handle)) {
|
||||
if (typeof key !== "symbol") {
|
||||
continue;
|
||||
}
|
||||
const name = String(key);
|
||||
if (name === "Symbol(kFd)") {
|
||||
mutableHandle[key] = -1;
|
||||
continue;
|
||||
}
|
||||
if (name === "Symbol(kRefs)") {
|
||||
mutableHandle[key] = 0;
|
||||
continue;
|
||||
}
|
||||
if (name === "Symbol(kClosePromise)") {
|
||||
mutableHandle[key] = undefined;
|
||||
}
|
||||
function releaseAllLocksSync(): void {
|
||||
for (const [normalizedFile, held] of HELD_LOCKS) {
|
||||
// Let the OS close live descriptors on process exit. On Linux/macOS this
|
||||
// avoids Node's unmanaged-fd warnings while still unlinking the stale
|
||||
// lock path before the process is fully gone.
|
||||
rmLockPathSync(held.lockPath);
|
||||
HELD_LOCKS.delete(normalizedFile);
|
||||
}
|
||||
}
|
||||
|
||||
function releaseAllLocksSync(): void {
|
||||
for (const [normalizedFile, held] of HELD_LOCKS) {
|
||||
try {
|
||||
if (typeof held.handle.fd === "number" && held.handle.fd >= 0) {
|
||||
fsSync.closeSync(held.handle.fd);
|
||||
markFileHandleClosedSync(held.handle);
|
||||
}
|
||||
} catch {
|
||||
// Best-effort exit cleanup only.
|
||||
}
|
||||
try {
|
||||
fsSync.rmSync(held.lockPath, { force: true });
|
||||
} catch {
|
||||
// Best-effort exit cleanup only.
|
||||
}
|
||||
HELD_LOCKS.delete(normalizedFile);
|
||||
function rmLockPathSync(lockPath: string): void {
|
||||
try {
|
||||
fsSync.rmSync(lockPath, { force: true });
|
||||
} catch {
|
||||
// Best-effort exit cleanup only.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user