kiri-mcp-server 0.24.0 → 0.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/package.json +1 -1
- package/dist/src/daemon/daemon.js +55 -22
- package/dist/src/daemon/daemon.js.map +1 -1
- package/dist/src/daemon/lifecycle.d.ts +38 -0
- package/dist/src/daemon/lifecycle.d.ts.map +1 -1
- package/dist/src/daemon/lifecycle.js +128 -2
- package/dist/src/daemon/lifecycle.js.map +1 -1
- package/dist/src/daemon/zombie-detector.d.ts +70 -0
- package/dist/src/daemon/zombie-detector.d.ts.map +1 -0
- package/dist/src/daemon/zombie-detector.js +174 -0
- package/dist/src/daemon/zombie-detector.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Intelligent code context extraction for LLMs via Model Context Protocol
|
|
4
4
|
|
|
5
|
-
[](package.json)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
8
|
[](https://modelcontextprotocol.io/)
|
|
@@ -139,10 +139,10 @@ See [CHANGELOG.md](CHANGELOG.md) for release notes.
|
|
|
139
139
|
|
|
140
140
|
**Recent highlights:**
|
|
141
141
|
|
|
142
|
-
- **v0.
|
|
143
|
-
- **v0.
|
|
144
|
-
- **v0.
|
|
145
|
-
- **v0.
|
|
142
|
+
- **v0.24.2**: Zombie daemon auto-detection and cleanup (PR #169)
|
|
143
|
+
- **v0.24.1**: DaemonLifecycle stale lock detection (PR #168)
|
|
144
|
+
- **v0.24.0**: MCP connection auto-reconnect (PR #167)
|
|
145
|
+
- **v0.23.0**: `--full` option for kiri command (PR #166)
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
@@ -221,4 +221,4 @@ Built with [Model Context Protocol](https://modelcontextprotocol.io/), [DuckDB](
|
|
|
221
221
|
|
|
222
222
|
---
|
|
223
223
|
|
|
224
|
-
**Status**: v0.
|
|
224
|
+
**Status**: v0.24.1 (Beta) - Production-ready for MCP clients
|
package/dist/package.json
CHANGED
|
@@ -16,6 +16,7 @@ import { getSocketPath } from "../shared/utils/socket.js";
|
|
|
16
16
|
import { parsePositiveInt } from "../shared/utils/validation.js";
|
|
17
17
|
import { DaemonLifecycle } from "./lifecycle.js";
|
|
18
18
|
import { createSocketServer } from "./socket.js";
|
|
19
|
+
import { detectAndCleanupZombie, extractPidFromLockError, isDuckDBLockConflictError, } from "./zombie-detector.js";
|
|
19
20
|
/**
|
|
20
21
|
* CLI specification for kiri-daemon
|
|
21
22
|
*/
|
|
@@ -151,31 +152,63 @@ async function main() {
|
|
|
151
152
|
// データベースが存在しない場合、自動的にインデックスを作成
|
|
152
153
|
await ensureDatabaseIndexed(options.repoRoot, options.databasePath, options.allowDegrade, false);
|
|
153
154
|
// ServerRuntimeを作成(DuckDB接続、メトリクス、デグレード制御など)
|
|
155
|
+
// ゾンビdaemonによるDuckDBロック競合時は、ゾンビ検出・クリーンアップ後にリトライ
|
|
154
156
|
let runtime = null;
|
|
155
157
|
let watcher = null;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
158
|
+
const MAX_RUNTIME_RETRY_ATTEMPTS = 2;
|
|
159
|
+
const socketPath = options.socketPath || getSocketPath(options.databasePath, { ensureDir: true });
|
|
160
|
+
for (let attempt = 0; attempt < MAX_RUNTIME_RETRY_ATTEMPTS; attempt++) {
|
|
161
|
+
try {
|
|
162
|
+
const runtimeOptions = {
|
|
163
|
+
repoRoot: options.repoRoot,
|
|
164
|
+
databasePath: options.databasePath,
|
|
165
|
+
allowDegrade: options.allowDegrade,
|
|
166
|
+
allowWriteLock: true, // Daemon mode should auto-create security lock
|
|
167
|
+
};
|
|
168
|
+
if (options.securityConfigPath) {
|
|
169
|
+
runtimeOptions.securityConfigPath = options.securityConfigPath;
|
|
170
|
+
}
|
|
171
|
+
if (options.securityLockPath) {
|
|
172
|
+
runtimeOptions.securityLockPath = options.securityLockPath;
|
|
173
|
+
}
|
|
174
|
+
runtime = await createServerRuntime(runtimeOptions);
|
|
175
|
+
await lifecycle.log(`Runtime initialized for repo: ${options.repoRoot}`);
|
|
176
|
+
break; // 成功
|
|
165
177
|
}
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
catch (err) {
|
|
179
|
+
const error = err;
|
|
180
|
+
// DuckDBロック競合エラーの場合、ゾンビ検出・クリーンアップを試みる
|
|
181
|
+
if (isDuckDBLockConflictError(error) && attempt < MAX_RUNTIME_RETRY_ATTEMPTS - 1) {
|
|
182
|
+
const conflictingPid = extractPidFromLockError(error.message);
|
|
183
|
+
if (conflictingPid !== null) {
|
|
184
|
+
await lifecycle.log(`DuckDB lock conflict detected (PID ${conflictingPid}). Checking for zombie...`);
|
|
185
|
+
const cleaned = await detectAndCleanupZombie(conflictingPid, socketPath, {
|
|
186
|
+
// ログ出力を lifecycle.log と console.error の両方に出力
|
|
187
|
+
logger: (message) => {
|
|
188
|
+
console.error(`[Daemon] ${message}`);
|
|
189
|
+
lifecycle.log(message).catch(() => { });
|
|
190
|
+
},
|
|
191
|
+
// メトリクス記録
|
|
192
|
+
onZombieDetected: () => lifecycle.recordZombieDetected(),
|
|
193
|
+
onCleanupComplete: (success) => lifecycle.recordZombieCleanup(success),
|
|
194
|
+
});
|
|
195
|
+
if (cleaned) {
|
|
196
|
+
await lifecycle.log(`Zombie daemon cleaned up. Retrying...`);
|
|
197
|
+
// DuckDBがロックを解放するのを待つ
|
|
198
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
199
|
+
continue; // リトライ
|
|
200
|
+
}
|
|
201
|
+
// 正常動作中のdaemonがいる場合
|
|
202
|
+
await lifecycle.log(`Another daemon is running normally. Exiting.`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// リトライ不可またはリトライ失敗
|
|
206
|
+
await lifecycle.log(`Failed to create runtime: ${error.message}`);
|
|
207
|
+
console.error(`[Daemon] Failed to create runtime: ${error.message}`);
|
|
208
|
+
await lifecycle.removePidFile();
|
|
209
|
+
await lifecycle.releaseStartupLock();
|
|
210
|
+
process.exit(1);
|
|
168
211
|
}
|
|
169
|
-
runtime = await createServerRuntime(runtimeOptions);
|
|
170
|
-
await lifecycle.log(`Runtime initialized for repo: ${options.repoRoot}`);
|
|
171
|
-
}
|
|
172
|
-
catch (err) {
|
|
173
|
-
const error = err;
|
|
174
|
-
await lifecycle.log(`Failed to create runtime: ${error.message}`);
|
|
175
|
-
console.error(`[Daemon] Failed to create runtime: ${error.message}`);
|
|
176
|
-
await lifecycle.removePidFile();
|
|
177
|
-
await lifecycle.releaseStartupLock();
|
|
178
|
-
process.exit(1);
|
|
179
212
|
}
|
|
180
213
|
// ウォッチモードの設定(自動インクリメンタル再インデックス)
|
|
181
214
|
// 注意: watch modeの起動に失敗してもデーモン自体は継続起動する
|
|
@@ -205,9 +238,9 @@ async function main() {
|
|
|
205
238
|
}
|
|
206
239
|
}
|
|
207
240
|
// RPCハンドラを作成(既存のロジックを再利用)
|
|
241
|
+
// Note: runtimeはリトライループで必ず初期化されるか、初期化失敗時はprocess.exit(1)で終了する
|
|
208
242
|
const rpcHandler = createRpcHandler(runtime);
|
|
209
243
|
// ソケットサーバーを作成(プラットフォームに応じてUnixソケットまたはWindows名前付きパイプ)
|
|
210
|
-
const socketPath = options.socketPath || getSocketPath(options.databasePath, { ensureDir: true });
|
|
211
244
|
const closeServer = await createSocketServer({
|
|
212
245
|
socketPath,
|
|
213
246
|
onRequest: async (request) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../../src/daemon/daemon.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,WAAW,MAAM,oBAAoB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAgB,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../../src/daemon/daemon.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,WAAW,MAAM,oBAAoB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAgB,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAiB9B;;GAEG;AACH,MAAM,eAAe,GAAY;IAC/B,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,6EAA6E;IAC1F,OAAO,EAAE,WAAW,CAAC,OAAO;IAC5B,KAAK,EAAE,uBAAuB;IAC9B,QAAQ,EAAE;QACR;YACE,KAAK,EAAE,uBAAuB;YAC9B,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,sBAAsB;oBACnC,WAAW,EAAE,QAAQ;oBACrB,OAAO,EAAE,GAAG;iBACb;gBACD;oBACE,IAAI,EAAE,IAAI;oBACV,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,mEAAmE;oBAChF,WAAW,EAAE,QAAQ;iBACtB;aACF;SACF;QACD;YACE,KAAK,EAAE,kBAAkB;YACzB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,aAAa;oBACnB,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,wCAAwC;oBACrD,WAAW,EAAE,QAAQ;iBACtB;gBACD;oBACE,IAAI,EAAE,gBAAgB;oBACtB,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,qDAAqD;oBAClE,WAAW,EAAE,WAAW;oBACxB,OAAO,EAAE,GAAG;iBACb;aACF;SACF;QACD;YACE,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,6CAA6C;oBAC1D,OAAO,EAAE,KAAK;iBACf;gBACD;oBACE,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,+CAA+C;oBAC5D,WAAW,EAAE,MAAM;oBACnB,OAAO,EAAE,KAAK;iBACf;aACF;SACF;QACD;YACE,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,eAAe;oBACrB,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,gDAAgD;oBAC7D,OAAO,EAAE,KAAK;iBACf;gBACD;oBACE,IAAI,EAAE,iBAAiB;oBACvB,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,kCAAkC;oBAC/C,WAAW,EAAE,QAAQ;iBACtB;gBACD;oBACE,IAAI,EAAE,eAAe;oBACrB,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,yBAAyB;oBACtC,WAAW,EAAE,QAAQ;iBACtB;aACF;SACF;KACF;IACD,QAAQ,EAAE;QACR,6DAA6D;QAC7D,yCAAyC;QACzC,0CAA0C;KAC3C;CACF,CAAC;AAEF;;GAEG;AACH,SAAS,eAAe;IACtB,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;IAE9C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAE,MAAM,CAAC,IAA2B,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpF,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAC9B,MAAM,CAAC,EAAyB,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,cAAc,CAAC,CAChF,CAAC;IACF,MAAM,UAAU,GAAG,MAAM,CAAC,aAAa,CAAC;QACtC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAW,CAAC;QAC/C,CAAC,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAErD,OAAO;QACL,QAAQ;QACR,YAAY;QACZ,UAAU;QACV,SAAS,EAAG,MAAM,CAAC,KAAiB,IAAI,KAAK;QAC7C,UAAU,EAAE,gBAAgB,CAAC,MAAM,CAAC,QAA8B,EAAE,GAAG,EAAE,gBAAgB,CAAC;QAC1F,kBAAkB,EAAE,gBAAgB,CAClC,MAAM,CAAC,gBAAgB,CAAuB,EAC9C,CAAC,EACD,0BAA0B,CAC3B;QACD,YAAY,EAAG,MAAM,CAAC,eAAe,CAAa,IAAI,KAAK;QAC3D,kBAAkB,EAAE,MAAM,CAAC,iBAAiB,CAAuB;QACnE,gBAAgB,EAAE,MAAM,CAAC,eAAe,CAAuB;KAChE,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAExF,IAAI,CAAC;QACH,gBAAgB;QAChB,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,kBAAkB,EAAE,CAAC;QAC1D,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,0EAA0E,CAAC,CAAC;YAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,CAAC,GAAG,CAAC,iCAAiC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;QAE7E,aAAa;QACb,MAAM,SAAS,CAAC,aAAa,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAE9C,+BAA+B;QAC/B,MAAM,qBAAqB,CACzB,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,YAAY,EACpB,OAAO,CAAC,YAAY,EACpB,KAAK,CACN,CAAC;QAEF,6CAA6C;QAC7C,gDAAgD;QAChD,IAAI,OAAO,GAAyB,IAAI,CAAC;QACzC,IAAI,OAAO,GAAwB,IAAI,CAAC;QACxC,MAAM,0BAA0B,GAAG,CAAC,CAAC;QACrC,MAAM,UAAU,GACd,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEjF,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,0BAA0B,EAAE,OAAO,EAAE,EAAE,CAAC;YACtE,IAAI,CAAC;gBACH,MAAM,cAAc,GAA8C;oBAChE,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;oBAClC,YAAY,EAAE,OAAO,CAAC,YAAY;oBAClC,cAAc,EAAE,IAAI,EAAE,+CAA+C;iBACtE,CAAC;gBAEF,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;oBAC/B,cAAc,CAAC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;gBACjE,CAAC;gBACD,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;oBAC7B,cAAc,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;gBAC7D,CAAC;gBAED,OAAO,GAAG,MAAM,mBAAmB,CAAC,cAAc,CAAC,CAAC;gBACpD,MAAM,SAAS,CAAC,GAAG,CAAC,iCAAiC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACzE,MAAM,CAAC,KAAK;YACd,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,KAAK,GAAG,GAAY,CAAC;gBAE3B,sCAAsC;gBACtC,IAAI,yBAAyB,CAAC,KAAK,CAAC,IAAI,OAAO,GAAG,0BAA0B,GAAG,CAAC,EAAE,CAAC;oBACjF,MAAM,cAAc,GAAG,uBAAuB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAE9D,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;wBAC5B,MAAM,SAAS,CAAC,GAAG,CACjB,sCAAsC,cAAc,2BAA2B,CAChF,CAAC;wBAEF,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC,cAAc,EAAE,UAAU,EAAE;4BACvE,6CAA6C;4BAC7C,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE;gCAClB,OAAO,CAAC,KAAK,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;gCACrC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;4BACzC,CAAC;4BACD,UAAU;4BACV,gBAAgB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,oBAAoB,EAAE;4BACxD,iBAAiB,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAC,OAAO,CAAC;yBACvE,CAAC,CAAC;wBAEH,IAAI,OAAO,EAAE,CAAC;4BACZ,MAAM,SAAS,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;4BAC7D,sBAAsB;4BACtB,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;4BAC1D,SAAS,CAAC,OAAO;wBACnB,CAAC;wBAED,oBAAoB;wBACpB,MAAM,SAAS,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;oBACtE,CAAC;gBACH,CAAC;gBAED,kBAAkB;gBAClB,MAAM,SAAS,CAAC,GAAG,CAAC,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBAClE,OAAO,CAAC,KAAK,CAAC,sCAAsC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACrE,MAAM,SAAS,CAAC,aAAa,EAAE,CAAC;gBAChC,MAAM,SAAS,CAAC,kBAAkB,EAAE,CAAC;gBACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,uCAAuC;QACvC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,SAAS,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,SAAS,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YACtE,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YAEzE,OAAO,GAAG,IAAI,YAAY,CAAC;gBACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,UAAU,EAAE,OAAO,CAAC,UAAU;aAC/B,CAAC,CAAC;YAEH,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACxB,CAAC;YAAC,OAAO,UAAU,EAAE,CAAC;gBACpB,6BAA6B;gBAC7B,0BAA0B;gBAC1B,oBAAoB;gBACpB,MAAM,YAAY,GAAG,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC3F,MAAM,SAAS,CAAC,GAAG,CAAC,+BAA+B,YAAY,EAAE,CAAC,CAAC;gBACnE,OAAO,CAAC,KAAK,CAAC,kDAAkD,YAAY,EAAE,CAAC,CAAC;gBAChF,OAAO,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;gBAC9E,OAAO,CAAC,KAAK,CACX,4FAA4F,CAC7F,CAAC;gBACF,OAAO,GAAG,IAAI,CAAC;gBACf,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,8DAA8D;QAC9D,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAQ,CAAC,CAAC;QAE9C,qDAAqD;QACrD,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC;YAC3C,UAAU;YACV,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;gBAC3B,SAAS,CAAC,oBAAoB,EAAE,CAAC;gBACjC,IAAI,CAAC;oBACH,OAAO,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;gBACnC,CAAC;wBAAS,CAAC;oBACT,SAAS,CAAC,oBAAoB,EAAE,CAAC;gBACnC,CAAC;YACH,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACvB,MAAM,SAAS,CAAC,GAAG,CAAC,qBAAqB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC1D,OAAO,CAAC,KAAK,CAAC,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC/D,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,SAAS,CAAC,GAAG,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC;QAEjE,sBAAsB;QACtB,MAAM,SAAS,CAAC,kBAAkB,EAAE,CAAC;QAErC,mBAAmB;QACnB,SAAS,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE;YAC9B,MAAM,SAAS,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;YAC/C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;gBACjD,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;oBAC9B,YAAY;gBACd,CAAC,CAAC,CAAC;YACL,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC5C,MAAM,WAAW,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC7C,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACxB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,qBAAqB,EAAE,CAAC;QAElC,MAAM,SAAS,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QACnD,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,GAAY,CAAC;QAC3B,MAAM,SAAS,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,KAAK,CAAC,yBAAyB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxD,MAAM,SAAS,CAAC,aAAa,EAAE,CAAC;QAChC,MAAM,SAAS,CAAC,kBAAkB,EAAE,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,YAAY;AACZ,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACzB,OAAO,CAAC,KAAK,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -3,9 +3,27 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles PID file creation, idle timeout, health checks, and graceful shutdown.
|
|
5
5
|
*/
|
|
6
|
+
/**
|
|
7
|
+
* 指定したPIDのプロセスが存在するかチェック
|
|
8
|
+
*
|
|
9
|
+
* @param pid - チェックするプロセスID
|
|
10
|
+
* @returns プロセスが存在する場合はtrue
|
|
11
|
+
*/
|
|
12
|
+
export declare function isProcessRunning(pid: number): boolean;
|
|
6
13
|
/**
|
|
7
14
|
* PIDファイルとスタートアップロックを管理する
|
|
8
15
|
*/
|
|
16
|
+
/**
|
|
17
|
+
* ゾンビdaemon関連のメトリクス
|
|
18
|
+
*/
|
|
19
|
+
export interface ZombieMetrics {
|
|
20
|
+
/** ゾンビ検出回数 */
|
|
21
|
+
detectedTotal: number;
|
|
22
|
+
/** クリーンアップ成功回数 */
|
|
23
|
+
cleanupSuccessTotal: number;
|
|
24
|
+
/** クリーンアップ失敗回数 */
|
|
25
|
+
cleanupFailureTotal: number;
|
|
26
|
+
}
|
|
9
27
|
export declare class DaemonLifecycle {
|
|
10
28
|
private readonly databasePath;
|
|
11
29
|
private readonly idleTimeoutMinutes;
|
|
@@ -18,6 +36,9 @@ export declare class DaemonLifecycle {
|
|
|
18
36
|
private shutdownCallback?;
|
|
19
37
|
private readonly maxLogSizeBytes;
|
|
20
38
|
private readonly maxLogBackups;
|
|
39
|
+
private zombieDetectedTotal;
|
|
40
|
+
private zombieCleanupSuccessTotal;
|
|
41
|
+
private zombieCleanupFailureTotal;
|
|
21
42
|
constructor(databasePath: string, idleTimeoutMinutes?: number);
|
|
22
43
|
/**
|
|
23
44
|
* PIDファイルパスを取得
|
|
@@ -34,6 +55,9 @@ export declare class DaemonLifecycle {
|
|
|
34
55
|
/**
|
|
35
56
|
* スタートアップロックを取得(排他的作成)
|
|
36
57
|
*
|
|
58
|
+
* ロックファイルが存在しても、所有プロセスが死んでいればstale lockとして
|
|
59
|
+
* 自動的にクリーンアップして再取得を試みる。
|
|
60
|
+
*
|
|
37
61
|
* @returns ロック取得に成功した場合はtrue、他のプロセスが既にロック中の場合はfalse
|
|
38
62
|
*/
|
|
39
63
|
acquireStartupLock(): Promise<boolean>;
|
|
@@ -97,5 +121,19 @@ export declare class DaemonLifecycle {
|
|
|
97
121
|
* ファイルサイズが制限を超えた場合、自動的にローテーションを実行
|
|
98
122
|
*/
|
|
99
123
|
log(message: string): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* ゾンビdaemon検出を記録
|
|
126
|
+
*/
|
|
127
|
+
recordZombieDetected(): void;
|
|
128
|
+
/**
|
|
129
|
+
* ゾンビdaemonクリーンアップ結果を記録
|
|
130
|
+
*
|
|
131
|
+
* @param success - クリーンアップが成功した場合はtrue
|
|
132
|
+
*/
|
|
133
|
+
recordZombieCleanup(success: boolean): void;
|
|
134
|
+
/**
|
|
135
|
+
* ゾンビdaemon関連メトリクスのスナップショットを取得
|
|
136
|
+
*/
|
|
137
|
+
getZombieMetrics(): ZombieMetrics;
|
|
100
138
|
}
|
|
101
139
|
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/daemon/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,qBAAa,eAAe;
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/daemon/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAYrD;AAED;;GAEG;AACH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,cAAc;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB;IAClB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB;IAClB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,eAAe;IAiBxB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAjBrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,gBAAgB,CAAC,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4B;IAC5D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAa;IAG3C,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,yBAAyB,CAAK;IACtC,OAAO,CAAC,yBAAyB,CAAK;gBAGnB,YAAY,EAAE,MAAM,EACpB,kBAAkB,GAAE,MAAU;IAOjD;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;;;;OAOG;IACG,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;IAwF5C;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAWzC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAWpC;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAsB5C;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAQzC;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAO5B;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI/C;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAuBtB;;OAEG;IACH,qBAAqB,IAAI,IAAI;IAoB7B;;;;OAIG;YACW,iBAAiB;IAmC/B;;;;OAIG;IACG,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAezC;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAI5B;;;;OAIG;IACH,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAQ3C;;OAEG;IACH,gBAAgB,IAAI,aAAa;CAOlC"}
|
|
@@ -5,8 +5,25 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as fs from "fs/promises";
|
|
7
7
|
/**
|
|
8
|
-
* PID
|
|
8
|
+
* 指定したPIDのプロセスが存在するかチェック
|
|
9
|
+
*
|
|
10
|
+
* @param pid - チェックするプロセスID
|
|
11
|
+
* @returns プロセスが存在する場合はtrue
|
|
9
12
|
*/
|
|
13
|
+
export function isProcessRunning(pid) {
|
|
14
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
// シグナル0はプロセスを停止せず、存在チェックのみ
|
|
19
|
+
process.kill(pid, 0);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// ESRCHはプロセスが存在しないことを意味
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
10
27
|
export class DaemonLifecycle {
|
|
11
28
|
databasePath;
|
|
12
29
|
idleTimeoutMinutes;
|
|
@@ -19,6 +36,10 @@ export class DaemonLifecycle {
|
|
|
19
36
|
shutdownCallback;
|
|
20
37
|
maxLogSizeBytes = 10 * 1024 * 1024; // 10MB
|
|
21
38
|
maxLogBackups = 3;
|
|
39
|
+
// ゾンビdaemonメトリクス
|
|
40
|
+
zombieDetectedTotal = 0;
|
|
41
|
+
zombieCleanupSuccessTotal = 0;
|
|
42
|
+
zombieCleanupFailureTotal = 0;
|
|
22
43
|
constructor(databasePath, idleTimeoutMinutes = 5) {
|
|
23
44
|
this.databasePath = databasePath;
|
|
24
45
|
this.idleTimeoutMinutes = idleTimeoutMinutes;
|
|
@@ -47,6 +68,9 @@ export class DaemonLifecycle {
|
|
|
47
68
|
/**
|
|
48
69
|
* スタートアップロックを取得(排他的作成)
|
|
49
70
|
*
|
|
71
|
+
* ロックファイルが存在しても、所有プロセスが死んでいればstale lockとして
|
|
72
|
+
* 自動的にクリーンアップして再取得を試みる。
|
|
73
|
+
*
|
|
50
74
|
* @returns ロック取得に成功した場合はtrue、他のプロセスが既にロック中の場合はfalse
|
|
51
75
|
*/
|
|
52
76
|
async acquireStartupLock() {
|
|
@@ -58,7 +82,80 @@ export class DaemonLifecycle {
|
|
|
58
82
|
}
|
|
59
83
|
catch (err) {
|
|
60
84
|
if (err.code === "EEXIST") {
|
|
61
|
-
|
|
85
|
+
// ロックが stale(所有プロセスが死んでいる)かチェック
|
|
86
|
+
try {
|
|
87
|
+
const existingPidStr = await fs.readFile(this.startupLockPath, "utf-8");
|
|
88
|
+
const existingPid = parseInt(existingPidStr.trim(), 10);
|
|
89
|
+
if (!isNaN(existingPid) && !isProcessRunning(existingPid)) {
|
|
90
|
+
// Stale lock 検出 - 削除前に再検証(TOCTOU対策)
|
|
91
|
+
console.error(`[Daemon] Removing stale startup lock (PID ${existingPid} not running)`);
|
|
92
|
+
// PIDが再利用されていないか再確認
|
|
93
|
+
try {
|
|
94
|
+
const recheckPidStr = await fs.readFile(this.startupLockPath, "utf-8");
|
|
95
|
+
const recheckPid = parseInt(recheckPidStr.trim(), 10);
|
|
96
|
+
// PIDが一致し、まだプロセスが死んでいる場合のみ削除
|
|
97
|
+
if (!isNaN(recheckPid) &&
|
|
98
|
+
recheckPid === existingPid &&
|
|
99
|
+
!isProcessRunning(recheckPid)) {
|
|
100
|
+
await fs.unlink(this.startupLockPath);
|
|
101
|
+
// 再取得を試みる
|
|
102
|
+
try {
|
|
103
|
+
await fs.writeFile(this.startupLockPath, String(process.pid), {
|
|
104
|
+
flag: "wx",
|
|
105
|
+
});
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
catch (retryErr) {
|
|
109
|
+
// 再取得に失敗(他のプロセスが先に取得した)
|
|
110
|
+
if (retryErr.code === "EEXIST") {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
throw retryErr;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (recheckErr) {
|
|
118
|
+
// 再検証中にファイルが消えた(他のプロセスが処理した)
|
|
119
|
+
if (recheckErr.code === "ENOENT") {
|
|
120
|
+
// 消えたので再取得を試みる
|
|
121
|
+
try {
|
|
122
|
+
await fs.writeFile(this.startupLockPath, String(process.pid), {
|
|
123
|
+
flag: "wx",
|
|
124
|
+
});
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
catch (retryErr) {
|
|
128
|
+
if (retryErr.code === "EEXIST") {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
throw retryErr;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
throw recheckErr;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// 生きているプロセスがロックを保持している
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
catch (readErr) {
|
|
141
|
+
// ロックファイルを読めない場合は安全のため取得失敗とする
|
|
142
|
+
if (readErr.code !== "ENOENT") {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
// ENOENTの場合、ファイルが消えたので再取得を試みる
|
|
146
|
+
try {
|
|
147
|
+
await fs.writeFile(this.startupLockPath, String(process.pid), {
|
|
148
|
+
flag: "wx",
|
|
149
|
+
});
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
catch (retryErr) {
|
|
153
|
+
if (retryErr.code === "EEXIST") {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
throw retryErr;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
62
159
|
}
|
|
63
160
|
throw err;
|
|
64
161
|
}
|
|
@@ -262,5 +359,34 @@ export class DaemonLifecycle {
|
|
|
262
359
|
console.error(`Failed to write to log file: ${err}`);
|
|
263
360
|
}
|
|
264
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* ゾンビdaemon検出を記録
|
|
364
|
+
*/
|
|
365
|
+
recordZombieDetected() {
|
|
366
|
+
this.zombieDetectedTotal++;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* ゾンビdaemonクリーンアップ結果を記録
|
|
370
|
+
*
|
|
371
|
+
* @param success - クリーンアップが成功した場合はtrue
|
|
372
|
+
*/
|
|
373
|
+
recordZombieCleanup(success) {
|
|
374
|
+
if (success) {
|
|
375
|
+
this.zombieCleanupSuccessTotal++;
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
this.zombieCleanupFailureTotal++;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* ゾンビdaemon関連メトリクスのスナップショットを取得
|
|
383
|
+
*/
|
|
384
|
+
getZombieMetrics() {
|
|
385
|
+
return {
|
|
386
|
+
detectedTotal: this.zombieDetectedTotal,
|
|
387
|
+
cleanupSuccessTotal: this.zombieCleanupSuccessTotal,
|
|
388
|
+
cleanupFailureTotal: this.zombieCleanupFailureTotal,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
265
391
|
}
|
|
266
392
|
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/daemon/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAElC
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/daemon/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ゾンビdaemon検出・クリーンアップユーティリティ
|
|
3
|
+
*
|
|
4
|
+
* 「プロセス生存 + ソケット消失」状態のゾンビdaemonを検出し、
|
|
5
|
+
* DuckDBロック競合時に自動クリーンアップを行う。
|
|
6
|
+
*
|
|
7
|
+
* @see Issue #168 - ゾンビソケットの自動検出・クリーンアップ機能
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* ログ出力関数の型
|
|
11
|
+
* 依存性注入により、テスト時のモック化や出力先の統一が可能
|
|
12
|
+
*/
|
|
13
|
+
export type ZombieLogger = (message: string) => void;
|
|
14
|
+
/**
|
|
15
|
+
* ゾンビ検出・クリーンアップのオプション
|
|
16
|
+
*/
|
|
17
|
+
export interface ZombieDetectorOptions {
|
|
18
|
+
/** ログ出力関数(デフォルト: console.error) */
|
|
19
|
+
logger?: ZombieLogger;
|
|
20
|
+
/** ソケット接続タイムアウト(ミリ秒、デフォルト: 2000) */
|
|
21
|
+
socketTimeoutMs?: number;
|
|
22
|
+
/** SIGTERM後の待機時間(ミリ秒、デフォルト: 2000) */
|
|
23
|
+
gracefulShutdownTimeoutMs?: number;
|
|
24
|
+
/** ゾンビ検出時のコールバック */
|
|
25
|
+
onZombieDetected?: () => void;
|
|
26
|
+
/** クリーンアップ完了時のコールバック */
|
|
27
|
+
onCleanupComplete?: (success: boolean) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* DuckDBロック競合エラーメッセージからPIDを抽出
|
|
31
|
+
*
|
|
32
|
+
* エラー形式:
|
|
33
|
+
* "IO Error: Could not set lock on file \"/path/to/db\":
|
|
34
|
+
* Conflicting lock is held in /path/to/node (PID 38342) by user username"
|
|
35
|
+
*
|
|
36
|
+
* @param errorMessage - DuckDBエラーメッセージ
|
|
37
|
+
* @returns 抽出したPID、または抽出できない場合はnull
|
|
38
|
+
*/
|
|
39
|
+
export declare function extractPidFromLockError(errorMessage: string): number | null;
|
|
40
|
+
/**
|
|
41
|
+
* DuckDBロック競合エラーかどうかを判定
|
|
42
|
+
*
|
|
43
|
+
* @param error - チェックするエラー
|
|
44
|
+
* @returns DuckDBロック競合エラーの場合はtrue
|
|
45
|
+
*/
|
|
46
|
+
export declare function isDuckDBLockConflictError(error: unknown): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* 指定PIDのプロセスがソケットをリッスンしているか確認
|
|
49
|
+
*
|
|
50
|
+
* ソケット接続を試み、pingレスポンスを確認することで
|
|
51
|
+
* プロセスが正常に動作中かを判定
|
|
52
|
+
*
|
|
53
|
+
* @param socketPath - ソケットファイルのパス
|
|
54
|
+
* @param timeoutMs - タイムアウト時間(ミリ秒)
|
|
55
|
+
* @returns プロセスがソケットをリッスンしている場合はtrue
|
|
56
|
+
*/
|
|
57
|
+
export declare function isProcessListeningOnSocket(socketPath: string, timeoutMs?: number): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* ゾンビプロセスを検出してクリーンアップ
|
|
60
|
+
*
|
|
61
|
+
* プロセスが存在するがソケットをリッスンしていない場合、
|
|
62
|
+
* ゾンビと判定してSIGTERM→SIGKILLで停止する。
|
|
63
|
+
*
|
|
64
|
+
* @param pid - 競合しているプロセスのPID
|
|
65
|
+
* @param socketPath - ソケットファイルのパス
|
|
66
|
+
* @param options - オプション(ログ、タイムアウト、コールバック)
|
|
67
|
+
* @returns クリーンアップ成功(またはプロセス不在)時はtrue、正常動作中のdaemonがいる場合はfalse
|
|
68
|
+
*/
|
|
69
|
+
export declare function detectAndCleanupZombie(pid: number, socketPath: string, options?: ZombieDetectorOptions): Promise<boolean>;
|
|
70
|
+
//# sourceMappingURL=zombie-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zombie-detector.d.ts","sourceRoot":"","sources":["../../../src/daemon/zombie-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,mCAAmC;IACnC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,oCAAoC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qCAAqC;IACrC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,oBAAoB;IACpB,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,wBAAwB;IACxB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD;AAKD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3E;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMjE;AAED;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAa,GACvB,OAAO,CAAC,OAAO,CAAC,CAiDlB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,OAAO,CAAC,CAgFlB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ゾンビdaemon検出・クリーンアップユーティリティ
|
|
3
|
+
*
|
|
4
|
+
* 「プロセス生存 + ソケット消失」状態のゾンビdaemonを検出し、
|
|
5
|
+
* DuckDBロック競合時に自動クリーンアップを行う。
|
|
6
|
+
*
|
|
7
|
+
* @see Issue #168 - ゾンビソケットの自動検出・クリーンアップ機能
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
import net from "net";
|
|
11
|
+
import { isProcessRunning } from "./lifecycle.js";
|
|
12
|
+
/** デフォルトのロガー */
|
|
13
|
+
const defaultLogger = (message) => console.error(`[Daemon] ${message}`);
|
|
14
|
+
/**
|
|
15
|
+
* DuckDBロック競合エラーメッセージからPIDを抽出
|
|
16
|
+
*
|
|
17
|
+
* エラー形式:
|
|
18
|
+
* "IO Error: Could not set lock on file \"/path/to/db\":
|
|
19
|
+
* Conflicting lock is held in /path/to/node (PID 38342) by user username"
|
|
20
|
+
*
|
|
21
|
+
* @param errorMessage - DuckDBエラーメッセージ
|
|
22
|
+
* @returns 抽出したPID、または抽出できない場合はnull
|
|
23
|
+
*/
|
|
24
|
+
export function extractPidFromLockError(errorMessage) {
|
|
25
|
+
const match = errorMessage.match(/\(PID\s+(\d+)\)/);
|
|
26
|
+
if (!match || !match[1])
|
|
27
|
+
return null;
|
|
28
|
+
const pid = parseInt(match[1], 10);
|
|
29
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* DuckDBロック競合エラーかどうかを判定
|
|
33
|
+
*
|
|
34
|
+
* @param error - チェックするエラー
|
|
35
|
+
* @returns DuckDBロック競合エラーの場合はtrue
|
|
36
|
+
*/
|
|
37
|
+
export function isDuckDBLockConflictError(error) {
|
|
38
|
+
if (!(error instanceof Error))
|
|
39
|
+
return false;
|
|
40
|
+
return (error.message.includes("Could not set lock on file") &&
|
|
41
|
+
error.message.includes("Conflicting lock"));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 指定PIDのプロセスがソケットをリッスンしているか確認
|
|
45
|
+
*
|
|
46
|
+
* ソケット接続を試み、pingレスポンスを確認することで
|
|
47
|
+
* プロセスが正常に動作中かを判定
|
|
48
|
+
*
|
|
49
|
+
* @param socketPath - ソケットファイルのパス
|
|
50
|
+
* @param timeoutMs - タイムアウト時間(ミリ秒)
|
|
51
|
+
* @returns プロセスがソケットをリッスンしている場合はtrue
|
|
52
|
+
*/
|
|
53
|
+
export async function isProcessListeningOnSocket(socketPath, timeoutMs = 2000) {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const socket = net.connect(socketPath);
|
|
56
|
+
const timeout = setTimeout(() => {
|
|
57
|
+
socket.destroy();
|
|
58
|
+
resolve(false);
|
|
59
|
+
}, timeoutMs);
|
|
60
|
+
let responseReceived = false;
|
|
61
|
+
socket.on("connect", () => {
|
|
62
|
+
// pingリクエストを送信
|
|
63
|
+
const pingRequest = {
|
|
64
|
+
jsonrpc: "2.0",
|
|
65
|
+
id: 1,
|
|
66
|
+
method: "ping",
|
|
67
|
+
};
|
|
68
|
+
socket.write(JSON.stringify(pingRequest) + "\n");
|
|
69
|
+
});
|
|
70
|
+
socket.on("data", (data) => {
|
|
71
|
+
if (responseReceived)
|
|
72
|
+
return;
|
|
73
|
+
try {
|
|
74
|
+
const response = JSON.parse(data.toString().trim());
|
|
75
|
+
// 正常なpingレスポンスを確認
|
|
76
|
+
if (response.result && response.result.status === "ok") {
|
|
77
|
+
responseReceived = true;
|
|
78
|
+
clearTimeout(timeout);
|
|
79
|
+
socket.end();
|
|
80
|
+
resolve(true);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
clearTimeout(timeout);
|
|
84
|
+
socket.destroy();
|
|
85
|
+
resolve(false);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
clearTimeout(timeout);
|
|
90
|
+
socket.destroy();
|
|
91
|
+
resolve(false);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
socket.on("error", () => {
|
|
95
|
+
clearTimeout(timeout);
|
|
96
|
+
resolve(false);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* ゾンビプロセスを検出してクリーンアップ
|
|
102
|
+
*
|
|
103
|
+
* プロセスが存在するがソケットをリッスンしていない場合、
|
|
104
|
+
* ゾンビと判定してSIGTERM→SIGKILLで停止する。
|
|
105
|
+
*
|
|
106
|
+
* @param pid - 競合しているプロセスのPID
|
|
107
|
+
* @param socketPath - ソケットファイルのパス
|
|
108
|
+
* @param options - オプション(ログ、タイムアウト、コールバック)
|
|
109
|
+
* @returns クリーンアップ成功(またはプロセス不在)時はtrue、正常動作中のdaemonがいる場合はfalse
|
|
110
|
+
*/
|
|
111
|
+
export async function detectAndCleanupZombie(pid, socketPath, options = {}) {
|
|
112
|
+
const { logger = defaultLogger, socketTimeoutMs = 2000, gracefulShutdownTimeoutMs = 2000, onZombieDetected, onCleanupComplete, } = options;
|
|
113
|
+
// プロセスが存在するか確認
|
|
114
|
+
if (!isProcessRunning(pid)) {
|
|
115
|
+
// プロセスが死んでいる(通常のstale lock)
|
|
116
|
+
logger(`Conflicting process (PID ${pid}) is no longer running`);
|
|
117
|
+
return true; // 呼び出し元でリトライ可能
|
|
118
|
+
}
|
|
119
|
+
// ソケットファイルが存在するか確認
|
|
120
|
+
// 注意: 既存daemonが異なる--socket-pathで起動されていた場合、
|
|
121
|
+
// このソケットパスへのpingは失敗するが、それはゾンビではない。
|
|
122
|
+
// ソケットファイルが存在しない場合のみゾンビとして扱う。
|
|
123
|
+
const socketExists = fs.existsSync(socketPath);
|
|
124
|
+
if (socketExists) {
|
|
125
|
+
// ソケットファイルが存在する場合、pingで応答確認
|
|
126
|
+
const isListening = await isProcessListeningOnSocket(socketPath, socketTimeoutMs);
|
|
127
|
+
if (isListening) {
|
|
128
|
+
// 正常に動作中のdaemon
|
|
129
|
+
logger(`Another daemon (PID ${pid}) is running normally`);
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
// ソケットファイルは存在するがpingに応答しない
|
|
133
|
+
// これは別の--socket-pathで起動されたdaemonの可能性があるため、
|
|
134
|
+
// 安全側に倒してkillしない
|
|
135
|
+
logger(`Another daemon (PID ${pid}) exists but not responding on this socket. ` +
|
|
136
|
+
`It may be using a different socket path. Not treating as zombie.`);
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
// ゾンビ状態: プロセス生存 + ソケットファイル消失
|
|
140
|
+
logger(`Detected zombie daemon (PID ${pid}): process alive but socket file does not exist`);
|
|
141
|
+
// ゾンビ検出コールバック
|
|
142
|
+
onZombieDetected?.();
|
|
143
|
+
try {
|
|
144
|
+
// SIGTERMでグレースフルシャットダウンを試みる
|
|
145
|
+
logger(`Sending SIGTERM to zombie daemon (PID ${pid})`);
|
|
146
|
+
process.kill(pid, "SIGTERM");
|
|
147
|
+
// グレースフルシャットダウン待機
|
|
148
|
+
const waitIterations = Math.ceil(gracefulShutdownTimeoutMs / 100);
|
|
149
|
+
for (let i = 0; i < waitIterations; i++) {
|
|
150
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
151
|
+
if (!isProcessRunning(pid)) {
|
|
152
|
+
logger(`Zombie daemon (PID ${pid}) terminated gracefully`);
|
|
153
|
+
onCleanupComplete?.(true);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// SIGKILLで強制終了
|
|
158
|
+
logger(`Force killing zombie daemon (PID ${pid}) with SIGKILL`);
|
|
159
|
+
process.kill(pid, "SIGKILL");
|
|
160
|
+
// 少し待機
|
|
161
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
162
|
+
onCleanupComplete?.(true);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
// 権限不足などでkillできない場合
|
|
167
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
168
|
+
logger(`Failed to kill zombie daemon (PID ${pid}): ${errorMessage}`);
|
|
169
|
+
logger(`Please manually terminate the process: kill ${pid}`);
|
|
170
|
+
onCleanupComplete?.(false);
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=zombie-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zombie-detector.js","sourceRoot":"","sources":["../../../src/daemon/zombie-detector.ts"],"names":[],"mappings":"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"}
|