{"record":{"id":"64322dd5d4dc1da6","repo":"thedotmack/claude-mem","slug":"graceful-shutdown-deadline-exceeded-proceeding","errorCode":null,"errorMessage":"Graceful shutdown deadline exceeded — proceeding","messagePattern":"Graceful shutdown deadline exceeded — proceeding","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/worker-shutdown.ts","lineNumber":115,"sourceCode":"    const outcome = await Promise.race([\n      options.performGracefulShutdown().then(\n        () => 'graceful' as const,\n        (error: unknown) => {\n          // A failed graceful shutdown must not abort the restart handoff;\n          // proceed exactly like the deadline path.\n          logger.error(\n            'SYSTEM',\n            'Graceful shutdown failed — proceeding',\n            { reason: options.reason },\n            error instanceof Error ? error : new Error(String(error))\n          );\n          return 'graceful-error' as const;\n        }\n      ),\n      deadline,\n    ]);\n    if (outcome === 'deadline') {\n      logger.warn('SYSTEM', 'Graceful shutdown deadline exceeded — proceeding', {\n        deadlineMs: options.gracefulDeadlineMs,\n        reason: options.reason,\n      });\n    }\n  } finally {\n    if (deadlineTimer !== undefined) clearTimeout(deadlineTimer);\n  }\n\n  // Successor handoff — ONLY for restart; 'stop' and signal shutdowns stay\n  // kill-only. The old worker spawns its replacement as its final act, after\n  // its port is confirmed free, so the successor never races the corpse for\n  // the port. CLI `claude-mem restart` is the caller. Hook version-mismatch\n  // recycles (ensureWorkerRunning in src/shared/worker-utils.ts) never reach\n  // this: they SIGKILL the stale worker and lazy-spawn the resolved version\n  // themselves, because this handoff runs the DYING install's resolver — a\n  // stale install would respawn its own version forever (#3378). This runs\n  // inside flushResponseThen's flushed action, so it completes before that\n  // helper's process.exit(0).","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/worker-shutdown.ts#L97-L133","documentation":"runShutdownSequence races graceful cleanup against a deadline. When the graceful branch loses the race, the sequence logs that the deadline was exceeded and proceeds (exits) anyway rather than hanging forever. In-flight work may be truncated.","triggerScenarios":"The graceful shutdown work (flushing observations, SDK queries, HTTP shutdown POST) did not complete before options.gracefulDeadlineMs elapsed, so Promise.race resolved with 'deadline' and the warn fires.","commonSituations":"Slow disk or DB making observation flush exceed the deadline; an SDK query hanging during shutdown; deadline configured too aggressively for the machine; large queue of pending memory writes at exit.","solutions":["Increase gracefulDeadlineMs in shutdown options to cover worst-case flush time","Check what the graceful branch was doing (queue depth, SDK logs) when it timed out","Reduce pending work at shutdown time (flush more frequently during operation)","Ensure the SDK subprocess is killed promptly so it cannot block the race"],"exampleFix":"// before\nrunShutdownSequence({ gracefulDeadlineMs: 3000, ... })\n// after\nrunShutdownSequence({ gracefulDeadlineMs: 10000, ... })","handlingStrategy":"try-catch","validationCode":"// Estimate flush time before entering shutdown\nconst pending = getPendingObservationCount();\nconst safeDeadline = Math.max(gracefulDeadlineMs, pending * PER_ITEM_MS + 2000);","typeGuard":null,"tryCatchPattern":"try {\n  await runShutdownSequence({ gracefulDeadlineMs: 10000, ... });\n} finally {\n  // exit anyway; deadline already enforced internally\n}","preventionTips":["Set gracefulDeadlineMs generously relative to flush volume","Flush observations incrementally so shutdown has little pending work","Monitor deadline-exceeded warnings to tune the timeout"],"tags":["shutdown","deadline","timeout","worker"],"backgroundTag":"request-timeout","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"}