fix: stop gmail watcher restart on bind error
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
- CLI: auto-migrate legacy config entries on command start (same behavior as gateway startup).
|
- CLI: auto-migrate legacy config entries on command start (same behavior as gateway startup).
|
||||||
- Auth: prioritize OAuth profiles but fall back to API keys when refresh fails; stored profiles now load without explicit auth order.
|
- Auth: prioritize OAuth profiles but fall back to API keys when refresh fails; stored profiles now load without explicit auth order.
|
||||||
- Docs: add group chat participation guidance to the AGENTS template.
|
- Docs: add group chat participation guidance to the AGENTS template.
|
||||||
|
- Gmail: stop restart loop when `gog gmail watch serve` fails to bind (address already in use).
|
||||||
- Linux: auto-attempt lingering during onboarding (try without sudo, fallback to sudo) and prompt on install/restart to keep the gateway alive after logout/idle. Thanks @tobiasbischoff for PR #237.
|
- Linux: auto-attempt lingering during onboarding (try without sudo, fallback to sudo) and prompt on install/restart to keep the gateway alive after logout/idle. Thanks @tobiasbischoff for PR #237.
|
||||||
- TUI: migrate key handling to the updated pi-tui Key matcher API.
|
- TUI: migrate key handling to the updated pi-tui Key matcher API.
|
||||||
- Logging: redact sensitive tokens in verbose tool summaries by default (configurable patterns).
|
- Logging: redact sensitive tokens in verbose tool summaries by default (configurable patterns).
|
||||||
|
|||||||
14
src/hooks/gmail-watcher.test.ts
Normal file
14
src/hooks/gmail-watcher.test.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { isAddressInUseError } from "./gmail-watcher.js";
|
||||||
|
|
||||||
|
describe("gmail watcher", () => {
|
||||||
|
it("detects address already in use errors", () => {
|
||||||
|
expect(
|
||||||
|
isAddressInUseError(
|
||||||
|
"listen tcp 127.0.0.1:8788: bind: address already in use",
|
||||||
|
),
|
||||||
|
).toBe(true);
|
||||||
|
expect(isAddressInUseError("EADDRINUSE: address already in use")).toBe(true);
|
||||||
|
expect(isAddressInUseError("some other error")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -20,6 +20,12 @@ import { ensureTailscaleEndpoint } from "./gmail-setup-utils.js";
|
|||||||
|
|
||||||
const log = createSubsystemLogger("gmail-watcher");
|
const log = createSubsystemLogger("gmail-watcher");
|
||||||
|
|
||||||
|
const ADDRESS_IN_USE_RE = /address already in use|EADDRINUSE/i;
|
||||||
|
|
||||||
|
export function isAddressInUseError(line: string): boolean {
|
||||||
|
return ADDRESS_IN_USE_RE.test(line);
|
||||||
|
}
|
||||||
|
|
||||||
let watcherProcess: ChildProcess | null = null;
|
let watcherProcess: ChildProcess | null = null;
|
||||||
let renewInterval: ReturnType<typeof setInterval> | null = null;
|
let renewInterval: ReturnType<typeof setInterval> | null = null;
|
||||||
let shuttingDown = false;
|
let shuttingDown = false;
|
||||||
@@ -61,6 +67,7 @@ async function startGmailWatch(
|
|||||||
function spawnGogServe(cfg: GmailHookRuntimeConfig): ChildProcess {
|
function spawnGogServe(cfg: GmailHookRuntimeConfig): ChildProcess {
|
||||||
const args = buildGogWatchServeArgs(cfg);
|
const args = buildGogWatchServeArgs(cfg);
|
||||||
log.info(`starting gog ${args.join(" ")}`);
|
log.info(`starting gog ${args.join(" ")}`);
|
||||||
|
let addressInUse = false;
|
||||||
|
|
||||||
const child = spawn("gog", args, {
|
const child = spawn("gog", args, {
|
||||||
stdio: ["ignore", "pipe", "pipe"],
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
@@ -74,7 +81,11 @@ function spawnGogServe(cfg: GmailHookRuntimeConfig): ChildProcess {
|
|||||||
|
|
||||||
child.stderr?.on("data", (data: Buffer) => {
|
child.stderr?.on("data", (data: Buffer) => {
|
||||||
const line = data.toString().trim();
|
const line = data.toString().trim();
|
||||||
if (line) log.warn(`[gog] ${line}`);
|
if (!line) return;
|
||||||
|
if (isAddressInUseError(line)) {
|
||||||
|
addressInUse = true;
|
||||||
|
}
|
||||||
|
log.warn(`[gog] ${line}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
child.on("error", (err) => {
|
child.on("error", (err) => {
|
||||||
@@ -83,6 +94,14 @@ function spawnGogServe(cfg: GmailHookRuntimeConfig): ChildProcess {
|
|||||||
|
|
||||||
child.on("exit", (code, signal) => {
|
child.on("exit", (code, signal) => {
|
||||||
if (shuttingDown) return;
|
if (shuttingDown) return;
|
||||||
|
if (addressInUse) {
|
||||||
|
log.warn(
|
||||||
|
"gog serve failed to bind (address already in use); stopping restarts. " +
|
||||||
|
"Another watcher is likely running. Set CLAWDBOT_SKIP_GMAIL_WATCHER=1 or stop the other process.",
|
||||||
|
);
|
||||||
|
watcherProcess = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
log.warn(`gog exited (code=${code}, signal=${signal}); restarting in 5s`);
|
log.warn(`gog exited (code=${code}, signal=${signal}); restarting in 5s`);
|
||||||
watcherProcess = null;
|
watcherProcess = null;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user