fix(ram): nur ein grosses Modell resident (Analyse starb im OOM-Killer)

rkllm_server braucht 6,5 GB von 7,74 GB. Blieb daneben ein anderer
Dauerhelfer resident, wurde rkllm beim Laden OOM-getoetet -- bei #101 in
allen 5 Startversuchen, weil das Retry nichts freigab. Ausloeser war der
warme CT2-Whisper-Daemon, den die 2-Sekunden-Aufnahme davor gestartet
hatte. Zweiter Fall: rkllm blieb nach der Analyse fuer immer resident, und
der Suchindex startete e5-small daneben.

gate.js bekommt eine Freigabe-Registry (registerReleaser/freeRam/
killAndWait, verdrahtet in server.js wie setProbe). Vor jedem rkllm-Versuch
und vor dem NPU-Whisper-Lauf werden die anderen Helfer beendet und ihr
Prozessende abgewartet; analyzeRecording gibt rkllm vor dem Suchindex frei.
Alle Helfer starten faul neu.

Verifiziert mit der Abfolge, die scheiterte: 12-s-Clip (CT2-Daemon
resident) -> Analyse #101 laeuft durch (221 s, done), rkllm lud in 22 s,
kein OOM, danach 5,3 GB frei statt 100 MB.
This commit is contained in:
2026-08-07 15:55:31 +02:00
parent c5daee25af
commit ff285011d2
8 changed files with 277 additions and 7 deletions
+8 -1
View File
@@ -12,6 +12,7 @@ import { spawn } from 'node:child_process';
import fs from 'node:fs';
import readline from 'node:readline';
import path from 'node:path';
import * as gate from './gate.js';
const PY = process.env.AIME_PY || '/opt/aime-venv/bin/python';
const DIR = process.env.AIME_EMB_DIR || '/opt/aime-models/e5-small';
@@ -91,4 +92,10 @@ export async function embedMany(texts) {
return out;
}
export function stop() { if (proc) { try { proc.kill(); } catch {} proc = null; ready = null; } }
// Beendet den Daemon und wartet auf sein Ende (siehe gate.freeRam: das e5-Modell
// hält in der Spitze 1,15 GB und muss weg, bevor rkllm lädt). Startet faul neu.
export function stop() {
const p = proc;
proc = null; ready = null; rl = null;
return gate.killAndWait(p);
}