From ddbfa838caeb60e8260603eb4ea5e11cf4c1547f Mon Sep 17 00:00:00 2001 From: jreakin Date: Tue, 31 Mar 2026 23:31:36 -0500 Subject: [PATCH] fix(embeddings): dispose ONNX Runtime session before process exit The ONNX Runtime inference session was never disposed after the embedding pipeline completed. When process.exit(0) fires, both ONNX Runtime's and LadybugDB's C++ atexit destructors run and race with each other, causing "mutex lock failed: Invalid argument" crashes. Add disposeEmbedder() call after embedding pipeline completes to properly release the ONNX session before LadybugDB closes and before process.exit(). Co-Authored-By: Claude Opus 4.6 (1M context) --- gitnexus/src/cli/analyze.ts | 2 ++ gitnexus/src/core/run-analyze.ts | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/gitnexus/src/cli/analyze.ts b/gitnexus/src/cli/analyze.ts index c77903de0..79f60b3fc 100644 --- a/gitnexus/src/cli/analyze.ts +++ b/gitnexus/src/cli/analyze.ts @@ -290,5 +290,7 @@ export const analyzeCommand = async (inputPath?: string, options?: AnalyzeOption // LadybugDB's native module holds open handles that prevent Node from exiting. // ONNX Runtime also registers native atexit hooks that segfault on some // platforms (#38, #40). Force-exit to ensure clean termination. + // The ONNX session is disposed in runFullAnalysis after embeddings complete + // to prevent C++ atexit destructors from racing with closed DB handles. process.exit(0); }; diff --git a/gitnexus/src/core/run-analyze.ts b/gitnexus/src/core/run-analyze.ts index e8a108c71..5d2684ec2 100644 --- a/gitnexus/src/core/run-analyze.ts +++ b/gitnexus/src/core/run-analyze.ts @@ -265,6 +265,15 @@ export async function runFullAnalysis( {}, cachedEmbeddingNodeIds.size > 0 ? cachedEmbeddingNodeIds : undefined, ); + + // Release ONNX Runtime session to prevent its C++ atexit handlers from + // racing with LadybugDB cleanup during process.exit() (#38, #40). + try { + const { disposeEmbedder } = await import('./embeddings/embedder.js'); + await disposeEmbedder(); + } catch { + /* best-effort */ + } } // ── Phase 5: Finalize (98–100%) ───────────────────────────────────