grepmax 0.14.7 → 0.14.9
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.
|
@@ -131,7 +131,10 @@ class Daemon {
|
|
|
131
131
|
stale: 120000,
|
|
132
132
|
onCompromised: () => {
|
|
133
133
|
console.error("[daemon] Lock compromised — another daemon took over. Shutting down.");
|
|
134
|
-
|
|
134
|
+
// Force exit after timeout — shutdown() is async and may not fully
|
|
135
|
+
// clear event loop references, leaving zombie daemon processes.
|
|
136
|
+
setTimeout(() => process.exit(1), 10000).unref();
|
|
137
|
+
this.shutdown().finally(() => process.exit(0));
|
|
135
138
|
},
|
|
136
139
|
});
|
|
137
140
|
(0, logger_1.debug)("daemon", "lock acquired");
|
|
@@ -143,20 +146,77 @@ class Daemon {
|
|
|
143
146
|
}
|
|
144
147
|
throw err;
|
|
145
148
|
}
|
|
146
|
-
// 2.
|
|
149
|
+
// 2. Stale socket cleanup + start socket server EARLY.
|
|
150
|
+
// The socket must be listening before the PID file is written so that
|
|
151
|
+
// other daemons checking isDaemonRunning() never see a PID for a process
|
|
152
|
+
// that can't respond to pings. Without this, the slow initialization
|
|
153
|
+
// steps below (LanceDB, MLX, project watchers) create a window where
|
|
154
|
+
// new daemons kill this one as "unresponsive".
|
|
155
|
+
try {
|
|
156
|
+
fs.unlinkSync(config_1.PATHS.daemonSocket);
|
|
157
|
+
}
|
|
158
|
+
catch (_b) { }
|
|
159
|
+
this.server = net.createServer((conn) => {
|
|
160
|
+
(0, logger_1.debug)("daemon", "client connected");
|
|
161
|
+
let buf = "";
|
|
162
|
+
conn.on("data", (chunk) => {
|
|
163
|
+
buf += chunk.toString();
|
|
164
|
+
if (buf.length > 1000000) {
|
|
165
|
+
conn.destroy();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const nl = buf.indexOf("\n");
|
|
169
|
+
if (nl === -1)
|
|
170
|
+
return;
|
|
171
|
+
const line = buf.slice(0, nl);
|
|
172
|
+
buf = buf.slice(nl + 1);
|
|
173
|
+
let cmd;
|
|
174
|
+
try {
|
|
175
|
+
cmd = JSON.parse(line);
|
|
176
|
+
}
|
|
177
|
+
catch (_a) {
|
|
178
|
+
conn.write(`${JSON.stringify({ ok: false, error: "invalid JSON" })}\n`);
|
|
179
|
+
conn.end();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
(0, ipc_handler_1.handleCommand)(this, cmd, conn).then((resp) => {
|
|
183
|
+
// null means the handler is managing the connection (streaming)
|
|
184
|
+
if (resp !== null) {
|
|
185
|
+
conn.write(`${JSON.stringify(resp)}\n`);
|
|
186
|
+
conn.end();
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
conn.on("error", () => { });
|
|
191
|
+
});
|
|
192
|
+
yield new Promise((resolve, reject) => {
|
|
193
|
+
this.server.on("error", (err) => {
|
|
194
|
+
const code = err.code;
|
|
195
|
+
if (code === "EADDRINUSE") {
|
|
196
|
+
console.error("[daemon] Socket already in use");
|
|
197
|
+
reject(err);
|
|
198
|
+
}
|
|
199
|
+
else if (code === "EOPNOTSUPP") {
|
|
200
|
+
console.error("[daemon] Filesystem does not support Unix sockets");
|
|
201
|
+
process.exitCode = 2;
|
|
202
|
+
reject(err);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
reject(err);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
this.server.listen(config_1.PATHS.daemonSocket, () => resolve());
|
|
209
|
+
});
|
|
210
|
+
// 3. Write PID file AFTER socket is listening — ensures any process that
|
|
211
|
+
// reads the PID can immediately ping this daemon and get a response.
|
|
212
|
+
fs.writeFileSync(config_1.PATHS.daemonPidFile, String(process.pid));
|
|
213
|
+
// 4. Kill existing per-project watchers
|
|
147
214
|
const existing = (0, watcher_store_1.listWatchers)();
|
|
148
215
|
for (const w of existing) {
|
|
149
216
|
console.log(`[daemon] Taking over from per-project watcher (PID: ${w.pid}, ${path.basename(w.projectRoot)})`);
|
|
150
217
|
yield (0, process_1.killProcess)(w.pid);
|
|
151
218
|
(0, watcher_store_1.unregisterWatcher)(w.pid);
|
|
152
219
|
}
|
|
153
|
-
// 3. Write PID file (informational only — lock is the real guard)
|
|
154
|
-
fs.writeFileSync(config_1.PATHS.daemonPidFile, String(process.pid));
|
|
155
|
-
// 4. Stale socket cleanup
|
|
156
|
-
try {
|
|
157
|
-
fs.unlinkSync(config_1.PATHS.daemonSocket);
|
|
158
|
-
}
|
|
159
|
-
catch (_b) { }
|
|
160
220
|
// 5. Open shared resources
|
|
161
221
|
try {
|
|
162
222
|
fs.mkdirSync(config_1.PATHS.cacheDir, { recursive: true });
|
|
@@ -219,58 +279,6 @@ class Daemon {
|
|
|
219
279
|
this.shutdown();
|
|
220
280
|
}
|
|
221
281
|
}, HEARTBEAT_INTERVAL_MS);
|
|
222
|
-
// 11. Socket server
|
|
223
|
-
this.server = net.createServer((conn) => {
|
|
224
|
-
(0, logger_1.debug)("daemon", "client connected");
|
|
225
|
-
let buf = "";
|
|
226
|
-
conn.on("data", (chunk) => {
|
|
227
|
-
buf += chunk.toString();
|
|
228
|
-
if (buf.length > 1000000) {
|
|
229
|
-
conn.destroy();
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
const nl = buf.indexOf("\n");
|
|
233
|
-
if (nl === -1)
|
|
234
|
-
return;
|
|
235
|
-
const line = buf.slice(0, nl);
|
|
236
|
-
buf = buf.slice(nl + 1);
|
|
237
|
-
let cmd;
|
|
238
|
-
try {
|
|
239
|
-
cmd = JSON.parse(line);
|
|
240
|
-
}
|
|
241
|
-
catch (_a) {
|
|
242
|
-
conn.write(`${JSON.stringify({ ok: false, error: "invalid JSON" })}\n`);
|
|
243
|
-
conn.end();
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
(0, ipc_handler_1.handleCommand)(this, cmd, conn).then((resp) => {
|
|
247
|
-
// null means the handler is managing the connection (streaming)
|
|
248
|
-
if (resp !== null) {
|
|
249
|
-
conn.write(`${JSON.stringify(resp)}\n`);
|
|
250
|
-
conn.end();
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
conn.on("error", () => { });
|
|
255
|
-
});
|
|
256
|
-
yield new Promise((resolve, reject) => {
|
|
257
|
-
this.server.on("error", (err) => {
|
|
258
|
-
const code = err.code;
|
|
259
|
-
if (code === "EADDRINUSE") {
|
|
260
|
-
console.error("[daemon] Socket already in use");
|
|
261
|
-
reject(err);
|
|
262
|
-
}
|
|
263
|
-
else if (code === "EOPNOTSUPP") {
|
|
264
|
-
console.error("[daemon] Filesystem does not support Unix sockets");
|
|
265
|
-
process.exitCode = 2;
|
|
266
|
-
reject(err);
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
reject(err);
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
this.server.listen(config_1.PATHS.daemonSocket, () => resolve());
|
|
273
|
-
});
|
|
274
282
|
console.log(`[daemon] Started (PID: ${process.pid}, ${this.processors.size} projects)`);
|
|
275
283
|
});
|
|
276
284
|
}
|
package/package.json
CHANGED