{"record":{"id":"26e796a229fc62c6","repo":"thedotmack/claude-mem","slug":"shutdown-already-in-progress-ignoring-re-entrant","errorCode":null,"errorMessage":"Shutdown already in progress — ignoring re-entrant shutdown request","messagePattern":"Shutdown already in progress — ignoring re-entrant shutdown request","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/services/worker-shutdown.ts","lineNumber":66,"sourceCode":"  removePidFile: () => void;\n  spawnDaemon: (scriptPath: string, port: number) => number | undefined;\n}\n\nexport interface ShutdownSequenceOptions {\n  reason: WorkerShutdownReason;\n  /** Reads the owner's shutdown flag (WorkerService.isShuttingDown). */\n  isShuttingDown: () => boolean;\n  markShuttingDown: () => void;\n  /** Pre-graceful bookkeeping: transcript watcher, heartbeat, sentinel, telemetry flush. */\n  beforeGracefulShutdown: () => Promise<void>;\n  performGracefulShutdown: () => Promise<void>;\n  gracefulDeadlineMs: number;\n  restartHandoff: RestartHandoffDeps;\n}\n\nexport async function runShutdownSequence(options: ShutdownSequenceOptions): Promise<void> {\n  if (options.isShuttingDown()) {\n    logger.warn('SYSTEM', 'Shutdown already in progress — ignoring re-entrant shutdown request', {\n      reason: options.reason,\n    });\n    return;\n  }\n  options.markShuttingDown();\n\n  try {\n    await options.beforeGracefulShutdown();\n  } catch (error: unknown) {\n    // Pre-graceful bookkeeping (watcher/heartbeat/sentinel/telemetry flush)\n    // failing must not abort the sequence: graceful shutdown and — for\n    // restarts — the successor handoff still have to run. Same \"proceed on\n    // error, never abort the handoff\" policy as performGracefulShutdown below.\n    logger.error(\n      'SYSTEM',\n      'Pre-graceful shutdown bookkeeping failed — proceeding',\n      { reason: options.reason },\n      error instanceof Error ? error : new Error(String(error))","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/worker-shutdown.ts#L48-L84","documentation":"runShutdownSequence guards against re-entrancy: if a shutdown is already in flight (flag set via markShuttingDown), a second shutdown request is logged and ignored. This prevents double-exit races, duplicate handoff attempts, and conflicting cleanup.","triggerScenarios":"shutdown() is invoked twice — e.g. SIGINT delivered twice, SIGTERM arriving during an in-progress restart handoff, or both an explicit restart request and an OS signal triggering shutdown concurrently.","commonSituations":"User presses Ctrl-C repeatedly while a restart handoff is verifying; container orchestrator sends SIGTERM followed by a second signal; systemd stop overlapping with an in-app restart call.","solutions":["No action needed — the first shutdown continues to completion","Avoid sending duplicate signals; use a single SIGTERM and wait for exit","If shutdown seems stuck, inspect logs for the in-flight shutdown's reason and deadline"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (isShuttingDown()) {\n  console.log('shutdown already in progress; skipping duplicate request');\n  return;\n}","typeGuard":null,"tryCatchPattern":"// Idempotent shutdown wrapper\nasync function shutdownOnce(reason) {\n  if (shuttingDown) return;\n  shuttingDown = true;\n  await runShutdownSequence({ reason, ... });\n}","preventionTips":["Make signal handlers idempotent","Guard shutdown entry points with a single boolean flag","Debounce repeated SIGINT/SIGTERM before invoking shutdown"],"tags":["shutdown","reentrancy","worker","signals"],"backgroundTag":"invalid-state-transition","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}