mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-11 03:38:07 +00:00
fix(server): skip the native close on analyze-worker SIGTERM cancellation (#2264 P2)
cancelJob() / the 30-min timeout (analyze-job.ts) send SIGTERM to the forked
analyze worker, but its SIGTERM handler still did a full `await closeLbug()`
(native conn/db teardown) — even though normal completion now skips it via
skipNativeCloseOnExit. A cancelled or timed-out --pdg server analyze could
therefore still hit the LadybugDB ClientContext destructor double-free, or block
behind the in-flight COPY's connection lock before exiting.
Mirror the CLI SIGINT path: a best-effort CHECKPOINT with
closeLbug({ skipNativeClose: true }) bounded by a 2s Promise.race timeout, then
process.exit(0) (which reclaims the handles). A CHECKPOINT failure is reported to
the parent over IPC rather than swallowed; the exit is in .finally so it always
fires.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JBJomjoTdBV2eveDVq4JMm
This commit is contained in:
parent
6514c4ab0e
commit
d5417cd6c0
1 changed files with 20 additions and 13 deletions
|
|
@ -73,19 +73,26 @@ process.on('unhandledRejection', (reason: unknown) => {
|
|||
}
|
||||
});
|
||||
|
||||
// Handle graceful shutdown — notify the parent over IPC, then exit. A cleanup
|
||||
// failure is reported to the parent (not swallowed), and the exit lives in
|
||||
// `finally` so it always fires even if a send() throws on a closed channel.
|
||||
process.on('SIGTERM', async () => {
|
||||
try {
|
||||
send({ type: 'error', message: 'Analysis cancelled (worker received SIGTERM)' });
|
||||
await closeLbug();
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : 'Worker cleanup failed during SIGTERM';
|
||||
send({ type: 'error', message });
|
||||
} finally {
|
||||
process.exit(0);
|
||||
}
|
||||
// Handle cancellation / timeout shutdown (analyze-job.ts `cancelJob` sends
|
||||
// SIGTERM). Mirror the CLI SIGINT path (#2264): a best-effort CHECKPOINT that
|
||||
// SKIPS the native close. A real conn.close()/db.close() here can double-free in
|
||||
// LadybugDB's ClientContext destructor after --pdg writes, AND it would block
|
||||
// behind the in-flight COPY's connection lock — so a single cancel could abort
|
||||
// the worker or hang until the COPY releases. Bound the CHECKPOINT with a short
|
||||
// timeout; process.exit reclaims the native handles regardless. A CHECKPOINT
|
||||
// failure is reported to the parent over IPC, not swallowed; the exit lives in
|
||||
// `finally` so it always fires.
|
||||
const SIGTERM_CLEANUP_TIMEOUT_MS = 2000;
|
||||
process.on('SIGTERM', () => {
|
||||
send({ type: 'error', message: 'Analysis cancelled (worker received SIGTERM)' });
|
||||
void Promise.race([
|
||||
closeLbug({ skipNativeClose: true }).catch((err: unknown) => {
|
||||
const message =
|
||||
err instanceof Error ? err.message : 'Worker checkpoint failed during SIGTERM';
|
||||
send({ type: 'error', message });
|
||||
}),
|
||||
new Promise<void>((resolve) => setTimeout(resolve, SIGTERM_CLEANUP_TIMEOUT_MS)),
|
||||
]).finally(() => process.exit(0));
|
||||
});
|
||||
|
||||
// Listen for start command from parent — guarded against re-entry
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue