Fix: Engine-Update lief ins Leere (falsches Skript gepinnt) + Text-file-busy

ROOT CAUSE: Die Unit pinnte MC_ENGINE_UPDATE_CMD=/usr/local/bin/update-llamacpp —
ein Alt-Skript aus der ROCm-Zeit, das den ROCm-Build nach /opt/llamacpp (totes
Rollback-Dir) zog statt des aktiven Vulkan-Builds nach /opt/llamacpp-vulkan. Es
endete mit 0 → Job "DONE", aber die aktive Engine blieb auf 9821. Mein
deploy/update-engine.sh lag dadurch komplett brach. Fix: Pin aus der Unit raus →
Backend nutzt den Default `sudo bash <repo>/deploy/update-engine.sh`.

Zusätzlich (vom User vermutet): mit geladenem Modell laeuft llama-server → die
Binary ist "Text file busy", in-place ueberschreiben scheitert. update-engine.sh
und update-swap.sh stoppen llama-swap jetzt VOR dem Austausch und starten danach,
mit robustem Fehlerpfad (set -uo statt -e, Service kommt immer zurueck, sonst
Rollback aus .bak).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-28 11:52:49 +02:00
parent 71d1d99c44
commit d73075bea0
3 changed files with 87 additions and 67 deletions
+4 -1
View File
@@ -20,7 +20,10 @@ Environment=MC_CONFIG_PATH=/etc/llama-swap/config.yaml
Environment=MC_MODELS_DIR=/srv/models
# Geteiltes Gedächtnis = die bestehende v1-DB (Kontinuität bis/über Cutover).
Environment=MC_MEMORY_DB=/srv/models/mission-control-memory.db
Environment=MC_ENGINE_UPDATE_CMD=/usr/local/bin/update-llamacpp
# KEIN MC_ENGINE_UPDATE_CMD-Override mehr: Das alte /usr/local/bin/update-llamacpp zog den
# ROCm-Build nach /opt/llamacpp (totes Rollback-Dir) statt des aktiven Vulkan-Builds → Updates
# liefen ins Leere ("DONE", aber nichts passierte). Ohne Override nutzt das Backend den Default
# `sudo bash <repo>/deploy/update-engine.sh` (Vulkan, mit Backup/Stack-Check/Auto-Rollback).
Restart=on-failure
RestartSec=3
+44 -33
View File
@@ -1,24 +1,38 @@
#!/usr/bin/env bash
# Aktualisiert den Vulkan-llama.cpp-Build auf den neuesten ggml-org-Release.
# Wird vom MC2-„Engine Update"-Button via `sudo bash …` als ROOT aufgerufen
# (deshalb KEIN internes sudo). Startet llama-swap neu, VERIFIZIERT den Stack
# (stack-postcheck.sh) und ROLLT bei Fehler automatisch auf den vorherigen Build zurück.
# Aktualisiert den Vulkan-llama.cpp-Build (ggml-org) auf den neuesten Release.
# Wird vom MC2-„Engine Update"-Button via `sudo bash …` als ROOT aufgerufen (kein internes sudo).
#
# Wichtig: llama-swap wird VOR dem Datei-Austausch gestoppt — sonst ist die laufende llama-server-
# Binary „Text file busy" und die mmap'ten .so-Libs dürfen nicht unter dem laufenden Prozess
# getauscht werden. Danach Stack-Check (echte Inferenz); bei Fehler Auto-Rollback.
#
# Exit 0 = neuer Build verifiziert · 1 = fehlgeschlagen, Rollback ok (alter Build läuft)
# · 2 = Update UND Rollback fehlgeschlagen (Stack evtl. kaputt — bitte prüfen)
set -euo pipefail
set -uo pipefail # bewusst KEIN -e: bei Fehlern kontrolliert zurückrollen statt hart abbrechen
VULKAN_DIR=/opt/llamacpp-vulkan
BAK_DIR=/opt/llamacpp-vulkan.bak # „letzter funktionierender Build" für Auto-Rollback
SRC_DIR="$(cd "$(dirname "$0")" && pwd)"
PIN_BUILD="${MC_ENGINE_BUILD:-}" # leer = neuester Release
die(){ echo "$1" >&2; exit 1; }
start_swap(){ systemctl start llama-swap || systemctl restart llama-swap; }
# Inhalte von $1 nach $VULKAN_DIR spiegeln (Dir vorher leeren → sauberer Austausch).
replace_dir(){
rm -rf "${VULKAN_DIR:?}" && mkdir -p "$VULKAN_DIR" || return 1
cp -a "$1/." "$VULKAN_DIR"/ || return 1
ln -sfn "$VULKAN_DIR/llama-server" /usr/local/bin/llama-server
[ -x "$VULKAN_DIR/llama-server" ]
}
# 1. Release ermitteln + laden (vor jedem Eingriff am laufenden System)
if [ -n "$PIN_BUILD" ]; then
TAG="$PIN_BUILD"
else
TAG="$(curl -s https://api.github.com/repos/ggml-org/llama.cpp/releases/latest | jq -r .tag_name)"
fi
[ -n "$TAG" ] && [ "$TAG" != "null" ] || { echo "Konnte neuesten Release-Tag nicht ermitteln"; exit 1; }
[ -n "$TAG" ] && [ "$TAG" != "null" ] || die "Konnte neuesten Release-Tag nicht ermitteln"
ASSET="llama-${TAG}-bin-ubuntu-vulkan-x64.tar.gz"
URL="https://github.com/ggml-org/llama.cpp/releases/download/${TAG}/${ASSET}"
@@ -26,42 +40,39 @@ TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
echo "Lade Engine ${TAG}"
curl -fsSL -o "$TMP/v.tgz" "$URL"
tar xzf "$TMP/v.tgz" -C "$TMP"
curl -fsSL -o "$TMP/v.tgz" "$URL" || die "Download fehlgeschlagen"
tar xzf "$TMP/v.tgz" -C "$TMP" || die "Entpacken fehlgeschlagen"
NEWDIR="$(echo "$TMP"/llama-*/)" # Tarball entpackt nach llama-<tag>/
[ -x "${NEWDIR}llama-server" ] || die "llama-server im Archiv nicht gefunden (${NEWDIR})"
# Sicherung des aktuellen (funktionierenden) Builds VOR dem Überschreiben → Auto-Rollback.
if [ -d "$VULKAN_DIR" ]; then
echo "Sichere aktuellen Build → ${BAK_DIR}"
rm -rf "$BAK_DIR"
cp -a "$VULKAN_DIR" "$BAK_DIR"
fi
# 2. Aktuellen (funktionierenden) Build sichern → Auto-Rollback
echo "Sichere aktuellen Build → ${BAK_DIR}"
rm -rf "$BAK_DIR"
cp -a "$VULKAN_DIR" "$BAK_DIR" || die "Backup fehlgeschlagen"
mkdir -p "$VULKAN_DIR"
cp -rf "$TMP"/llama-*/. "$VULKAN_DIR"/
test -x "$VULKAN_DIR/llama-server"
ln -sfn "$VULKAN_DIR/llama-server" /usr/local/bin/llama-server
systemctl restart llama-swap
echo "Engine auf ${TAG} aktualisiert — verifiziere Stack…"
if bash "$SRC_DIR/stack-postcheck.sh"; then
# 3. llama-swap stoppen (gibt Binary/Libs frei), austauschen, wieder starten
echo "Stoppe llama-swap für den Austausch…"
systemctl stop llama-swap
if replace_dir "${NEWDIR%/}"; then
start_swap
echo "Engine auf ${TAG} aktualisiert — verifiziere Stack…"
if bash "$SRC_DIR/stack-postcheck.sh"; then
echo "Engine-Update ${TAG} erfolgreich verifiziert."
exit 0
fi
echo "!! Stack-Check fehlgeschlagen — ROLLBACK auf vorherigen Build."
else
echo "!! Datei-Austausch fehlgeschlagen — ROLLBACK auf vorherigen Build."
fi
# --- Auto-Rollback auf den gesicherten Build ---
echo "!! Stack-Check fehlgeschlagen — ROLLBACK auf vorherigen Build."
if [ -d "$BAK_DIR" ]; then
rm -rf "$VULKAN_DIR"
cp -a "$BAK_DIR" "$VULKAN_DIR"
ln -sfn "$VULKAN_DIR/llama-server" /usr/local/bin/llama-server
systemctl restart llama-swap
echo "Vorheriger Build wiederhergestellt — prüfe Stack erneut…"
# 4. Auto-Rollback auf den gesicherten Build
systemctl stop llama-swap
if replace_dir "$BAK_DIR"; then
start_swap
if bash "$SRC_DIR/stack-postcheck.sh"; then
echo "Rollback erfolgreich: vorheriger Build läuft wieder. (Update ${TAG} NICHT angewendet.)"
exit 1
fi
echo "!!! Rollback-Check ebenfalls fehlgeschlagen — Stack möglicherweise kaputt!"
exit 2
fi
echo "!!! Kein Backup vorhanden — Rollback nicht möglich!"
echo "!!! Rollback fehlgeschlagen — Stack möglicherweise kaputt! Backup liegt unter ${BAK_DIR}."
exit 2
+30 -24
View File
@@ -1,24 +1,28 @@
#!/usr/bin/env bash
# Aktualisiert den llama-swap-Router (mostlygeek/llama-swap) auf den neuesten Release.
# Wird vom MC2-„Router Update"-Button via `sudo bash …` als ROOT aufgerufen
# (deshalb KEIN internes sudo). Ersetzt die Binary, startet llama-swap neu, VERIFIZIERT
# den Stack (stack-postcheck.sh) und ROLLT bei Fehler automatisch auf die alte Binary zurück.
# Wird vom MC2-„Router Update"-Button via `sudo bash …` als ROOT aufgerufen (kein internes sudo).
#
# Wichtig: llama-swap wird VOR dem Binary-Tausch gestoppt — sonst ist die laufende Binary
# „Text file busy". Danach Stack-Check (echte Inferenz); bei Fehler Auto-Rollback.
#
# Exit 0 = neue Version verifiziert · 1 = fehlgeschlagen, Rollback ok (alte Version läuft)
# · 2 = Update UND Rollback fehlgeschlagen (Stack evtl. kaputt — bitte prüfen)
set -euo pipefail
set -uo pipefail # bewusst KEIN -e: bei Fehlern kontrolliert zurückrollen statt hart abbrechen
SWAP_BIN="${MC_SWAP_BIN:-/usr/local/bin/llama-swap}"
BAK="${SWAP_BIN}.bak" # „letzte funktionierende Version" für Auto-Rollback
SRC_DIR="$(cd "$(dirname "$0")" && pwd)"
PIN_VER="${MC_SWAP_VERSION:-}" # leer = neuester Release
die(){ echo "$1" >&2; exit 1; }
start_swap(){ systemctl start llama-swap || systemctl restart llama-swap; }
if [ -n "$PIN_VER" ]; then
TAG="$PIN_VER"
else
TAG="$(curl -s https://api.github.com/repos/mostlygeek/llama-swap/releases/latest | jq -r .tag_name)"
fi
[ -n "$TAG" ] && [ "$TAG" != "null" ] || { echo "Konnte neuesten Release-Tag nicht ermitteln"; exit 1; }
[ -n "$TAG" ] && [ "$TAG" != "null" ] || die "Konnte neuesten Release-Tag nicht ermitteln"
# Asset-Name nutzt die nackte Nummer (z.B. v230 -> 230): llama-swap_230_linux_amd64.tar.gz
NUM="${TAG#v}"
@@ -28,35 +32,37 @@ TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
echo "Lade llama-swap ${TAG}"
curl -fsSL -o "$TMP/s.tgz" "$URL"
tar xzf "$TMP/s.tgz" -C "$TMP"
curl -fsSL -o "$TMP/s.tgz" "$URL" || die "Download fehlgeschlagen"
tar xzf "$TMP/s.tgz" -C "$TMP" || die "Entpacken fehlgeschlagen"
NEW="$(find "$TMP" -type f -name llama-swap | head -1)"
[ -n "$NEW" ] || { echo "llama-swap-Binary im Archiv nicht gefunden"; exit 1; }
[ -n "$NEW" ] || die "llama-swap-Binary im Archiv nicht gefunden"
# Sicherung der aktuellen (funktionierenden) Binary VOR dem Überschreiben → Auto-Rollback.
[ -x "$SWAP_BIN" ] && cp -a "$SWAP_BIN" "$BAK"
install -m 0755 "$NEW" "$SWAP_BIN"
test -x "$SWAP_BIN"
systemctl restart llama-swap
# Sicherung der aktuellen (funktionierenden) Binary → Auto-Rollback
[ -x "$SWAP_BIN" ] && { cp -a "$SWAP_BIN" "$BAK" || die "Backup fehlgeschlagen"; }
echo "Router auf ${TAG} aktualisiert — verifiziere Stack…"
if bash "$SRC_DIR/stack-postcheck.sh"; then
# llama-swap stoppen (gibt die laufende Binary frei), tauschen, wieder starten
echo "Stoppe llama-swap für den Binary-Tausch…"
systemctl stop llama-swap
if install -m 0755 "$NEW" "$SWAP_BIN" && [ -x "$SWAP_BIN" ]; then
start_swap
echo "Router auf ${TAG} aktualisiert — verifiziere Stack…"
if bash "$SRC_DIR/stack-postcheck.sh"; then
echo "Router-Update ${TAG} erfolgreich verifiziert."
exit 0
fi
echo "!! Stack-Check fehlgeschlagen — ROLLBACK auf vorherige Version."
else
echo "!! Binary-Tausch fehlgeschlagen — ROLLBACK auf vorherige Version."
fi
# --- Auto-Rollback auf die gesicherte Binary ---
echo "!! Stack-Check fehlgeschlagen — ROLLBACK auf vorherige Version."
if [ -x "$BAK" ]; then
cp -a "$BAK" "$SWAP_BIN"
systemctl restart llama-swap
echo "Vorherige Binary wiederhergestellt — prüfe Stack erneut…"
# Auto-Rollback auf die gesicherte Binary
systemctl stop llama-swap
if [ -x "$BAK" ] && install -m 0755 "$BAK" "$SWAP_BIN"; then
start_swap
if bash "$SRC_DIR/stack-postcheck.sh"; then
echo "Rollback erfolgreich: vorherige llama-swap-Version läuft wieder. (Update ${TAG} NICHT angewendet.)"
exit 1
fi
echo "!!! Rollback-Check ebenfalls fehlgeschlagen — Stack möglicherweise kaputt!"
exit 2
fi
echo "!!! Kein Backup vorhanden — Rollback nicht möglich!"
echo "!!! Rollback fehlgeschlagen — Stack möglicherweise kaputt! Backup liegt unter ${BAK}."
exit 2