From d4f895d8f2a4f49e9280a1e1df44f98d30ee7273 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 25 Jan 2026 09:21:39 +0000 Subject: [PATCH] fix: move gateway lock to temp dir --- CHANGELOG.md | 1 + src/config/paths.ts | 11 +++++++++++ src/infra/gateway-lock.test.ts | 6 ++++-- src/infra/gateway-lock.ts | 5 +++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47ba3497c..126d379d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ Docs: https://docs.clawd.bot - Gateway: reduce log noise for late invokes + remote node probes; debounce skills refresh. (#1607) Thanks @petter-b. - Gateway: clarify Control UI/WebChat auth error hints for missing tokens. (#1690) - Gateway: listen on IPv6 loopback when bound to 127.0.0.1 so localhost webhooks work. +- Gateway: store lock files in the temp directory to avoid stale locks on persistent volumes. (#1676) - macOS: default direct-transport `ws://` URLs to port 18789; document `gateway.remote.transport`. (#1603) Thanks @ngutman. - Voice Call: return stream TwiML for outbound conversation calls on initial Twilio webhook. (#1634) - Google Chat: tighten email allowlist matching, typing cleanup, media caps, and onboarding/docs/tests. (#1635) Thanks @iHildy. diff --git a/src/config/paths.ts b/src/config/paths.ts index 6b1e4dcf7..c3151c1be 100644 --- a/src/config/paths.ts +++ b/src/config/paths.ts @@ -59,6 +59,17 @@ export const CONFIG_PATH_CLAWDBOT = resolveConfigPath(); export const DEFAULT_GATEWAY_PORT = 18789; +/** + * Gateway lock directory (ephemeral). + * Default: os.tmpdir()/clawdbot- (uid suffix when available). + */ +export function resolveGatewayLockDir(tmpdir: () => string = os.tmpdir): string { + const base = tmpdir(); + const uid = typeof process.getuid === "function" ? process.getuid() : undefined; + const suffix = uid != null ? `clawdbot-${uid}` : "clawdbot"; + return path.join(base, suffix); +} + const OAUTH_FILENAME = "oauth.json"; /** diff --git a/src/infra/gateway-lock.test.ts b/src/infra/gateway-lock.test.ts index 04b402b27..aac98bec5 100644 --- a/src/infra/gateway-lock.test.ts +++ b/src/infra/gateway-lock.test.ts @@ -7,12 +7,13 @@ import path from "node:path"; import { describe, expect, it, vi } from "vitest"; import { acquireGatewayLock, GatewayLockError } from "./gateway-lock.js"; -import { resolveConfigPath, resolveStateDir } from "../config/paths.js"; +import { resolveConfigPath, resolveGatewayLockDir, resolveStateDir } from "../config/paths.js"; async function makeEnv() { const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gateway-lock-")); const configPath = path.join(dir, "clawdbot.json"); await fs.writeFile(configPath, "{}", "utf8"); + await fs.mkdir(resolveGatewayLockDir(), { recursive: true }); return { env: { ...process.env, @@ -29,7 +30,8 @@ function resolveLockPath(env: NodeJS.ProcessEnv) { const stateDir = resolveStateDir(env); const configPath = resolveConfigPath(env, stateDir); const hash = createHash("sha1").update(configPath).digest("hex").slice(0, 8); - return { lockPath: path.join(stateDir, `gateway.${hash}.lock`), configPath }; + const lockDir = resolveGatewayLockDir(); + return { lockPath: path.join(lockDir, `gateway.${hash}.lock`), configPath }; } function makeProcStat(pid: number, startTime: number) { diff --git a/src/infra/gateway-lock.ts b/src/infra/gateway-lock.ts index 8a84c5e2f..4c5fe1bde 100644 --- a/src/infra/gateway-lock.ts +++ b/src/infra/gateway-lock.ts @@ -3,7 +3,7 @@ import fs from "node:fs/promises"; import fsSync from "node:fs"; import path from "node:path"; -import { resolveConfigPath, resolveStateDir } from "../config/paths.js"; +import { resolveConfigPath, resolveGatewayLockDir, resolveStateDir } from "../config/paths.js"; const DEFAULT_TIMEOUT_MS = 5000; const DEFAULT_POLL_INTERVAL_MS = 100; @@ -150,7 +150,8 @@ function resolveGatewayLockPath(env: NodeJS.ProcessEnv) { const stateDir = resolveStateDir(env); const configPath = resolveConfigPath(env, stateDir); const hash = createHash("sha1").update(configPath).digest("hex").slice(0, 8); - const lockPath = path.join(stateDir, `gateway.${hash}.lock`); + const lockDir = resolveGatewayLockDir(); + const lockPath = path.join(lockDir, `gateway.${hash}.lock`); return { lockPath, configPath }; }