studio: kill orphaned llama-server processes on startup

When the studio process is killed (SIGTERM/SIGKILL), atexit handlers
may not run in the subprocess orchestrator, leaving llama-server
processes orphaned and holding GPU memory. This caused OOM errors when
trying to load a new model after a studio restart.

On init, LlamaCppBackend now runs pgrep to find and SIGKILL any stale
llama-server processes before starting fresh.
This commit is contained in:
Daniel Han 2026-03-15 06:54:40 +00:00
commit c59f028150

View file

@ -49,6 +49,7 @@ class LlamaCppBackend:
self._stdout_lines: list[str] = []
self._stdout_thread: Optional[threading.Thread] = None
self._kill_orphaned_servers()
atexit.register(self._cleanup)
# ── Properties ────────────────────────────────────────────────
@ -706,6 +707,33 @@ class LlamaCppBackend:
self._stdout_thread.join(timeout = 2)
self._stdout_thread = None
@staticmethod
def _kill_orphaned_servers():
"""Kill any orphaned llama-server processes from previous studio runs."""
import os
import signal
try:
result = subprocess.run(
["pgrep", "-f", "llama-server"],
capture_output = True, text = True, timeout = 5,
)
if result.returncode != 0:
return
for line in result.stdout.strip().splitlines():
pid = int(line.strip())
if pid == os.getpid():
continue
try:
os.kill(pid, signal.SIGKILL)
logger.info(f"Killed orphaned llama-server process (pid={pid})")
except ProcessLookupError:
pass
except PermissionError:
pass
except Exception:
pass
def _cleanup(self):
"""atexit handler to ensure llama-server is terminated."""
self._kill_process()