Summary
All ruflo memory subcommands (init, stats, store, search, list, cleanup, compress) hang indefinitely after completing their work. The process never exits because ONNX/WASM worker threads keep the Node.js event loop alive.
Related: PR #1441 implements the fix.
Root Cause
When any memory subcommand runs, ensureInitialized() in memory-tools.ts loads the ONNX embedding model (all-MiniLM-L6-v2 via @xenova/transformers). The ONNX runtime spawns worker threads that are never terminated, preventing Node.js from exiting naturally after the command completes.
The CLI entry point (bin/cli.js) called cli.run() but never called process.exit(0) on success:
// Before (hangs):
cli.run().catch((error) => {
console.error('Fatal error:', error.message);
process.exit(1);
});
Only the error path had process.exit(). The success path relied on Node.js exiting naturally — which never happens because of the ONNX worker threads.
Why the fix belongs in bin/cli.js, not in individual commands
The original inline fix (issue #1428) placed setTimeout(() => process.exit(0), 500).unref() inside initMemoryCommand. This was wrong because:
-
Only fixed one command. Every memory subcommand triggers the same ONNX load via ensureInitialized(), so every one hangs. Fixing them individually requires 20+ call sites.
-
Commands shouldn't call process.exit(). A command's action function is a library method — it returns a result object ({ success, data }) to its caller. Calling process.exit() inside it breaks testability (process.exit mocks throw in tests) and violates separation of concerns.
-
The entry point is the right place. bin/cli.js is the process boundary. Adding .then(() => process.exit(0)) there means all commands benefit — memory, neural, or any future command that loads ONNX.
// After (exits cleanly):
cli.run().then(() => {
process.exit(0);
}).catch((error) => {
console.error('Fatal error:', error.message);
process.exit(1);
});
Also removed:
- The inline
setTimeout/process.exit hack from initMemoryCommand
- All
scheduleExit() call sites from memory.ts
Testing
# Before fix: hangs until killed
timeout 10 node bin/cli.js memory stats # exit 124 (timeout)
# After fix: exits immediately
timeout 10 node bin/cli.js memory stats # exit 0
Unit tests: 32 passed, 1 skipped (unchanged from baseline).
Environment
- Windows 11 / WSL2
- Node.js v20+
- Any platform where ONNX runtime loads successfully
Related
🤖 Generated with claude-flow
Summary
All
ruflo memorysubcommands (init,stats,store,search,list,cleanup,compress) hang indefinitely after completing their work. The process never exits because ONNX/WASM worker threads keep the Node.js event loop alive.Related: PR #1441 implements the fix.
Root Cause
When any memory subcommand runs,
ensureInitialized()inmemory-tools.tsloads the ONNX embedding model (all-MiniLM-L6-v2via@xenova/transformers). The ONNX runtime spawns worker threads that are never terminated, preventing Node.js from exiting naturally after the command completes.The CLI entry point (
bin/cli.js) calledcli.run()but never calledprocess.exit(0)on success:Only the error path had
process.exit(). The success path relied on Node.js exiting naturally — which never happens because of the ONNX worker threads.Why the fix belongs in
bin/cli.js, not in individual commandsThe original inline fix (issue #1428) placed
setTimeout(() => process.exit(0), 500).unref()insideinitMemoryCommand. This was wrong because:Only fixed one command. Every memory subcommand triggers the same ONNX load via
ensureInitialized(), so every one hangs. Fixing them individually requires 20+ call sites.Commands shouldn't call
process.exit(). A command'sactionfunction is a library method — it returns a result object ({ success, data }) to its caller. Callingprocess.exit()inside it breaks testability (process.exitmocks throw in tests) and violates separation of concerns.The entry point is the right place.
bin/cli.jsis the process boundary. Adding.then(() => process.exit(0))there means all commands benefit — memory, neural, or any future command that loads ONNX.Fix (PR #1441)
Also removed:
setTimeout/process.exithack frominitMemoryCommandscheduleExit()call sites frommemory.tsTesting
Unit tests: 32 passed, 1 skipped (unchanged from baseline).
Environment
Related
ruflo memory inithanging🤖 Generated with claude-flow