chore: Update-Skript erkennt Container-Zustand, Merkposten ergaenzt
CI / pruefen (pull_request) Canceled after 0s
CI / pruefen (pull_request) Canceled after 0s
Das Update-Skript prüfte allein http://127.0.0.1:APP_PORT/api/health. Hinter einem Reverse Proxy ist der App-Port oft gar nicht auf dem Host veröffentlicht — dann meldete das Skript nach zwei Minuten einen Fehlschlag, obwohl das Update sauber durchgelaufen war. Schlägt die Abfrage vom Host fehl, zählt jetzt der HEALTHCHECK des Containers. Den bringt das Image schon mit; er fragt /api/health von innen ab und ist damit unabhängig von der Portveröffentlichung. Im Fehlerfall nennt das Skript zusätzlich den Container-Zustand und ordnet ihn ein: kein Container (Start fehlgeschlagen), startet noch (Migrationen dauern), läuft aber ungesund (Fehler in der Anwendung), oder ein älteres Image ohne Healthcheck. Ohne diese Auskunft sah ein nicht veröffentlichter Port genauso aus wie eine abgestürzte Anwendung. container_zustand() gibt bewusst immer 0 zurück — unter set -e dürfte die Diagnose nicht selbst abbrechen, bevor der Weg zurück ausgegeben ist. Dazu drei Merkposten in CLAUDE.md, die diese Sitzung Zeit gekostet haben: Klickwege müssen gegen einen Produktionsbau geprüft werden (im Entwicklungsmodus hydratisiert unter headless Chromium nichts, weil der HMR-Socket scheitert — ohne jede Fehlermeldung), vor npm start den Port prüfen, und dass scripts/shot.mjs sich nicht anmeldet.
This commit is contained in:
@@ -96,6 +96,9 @@ Statistiken, Benachrichtigungen, REST-API, PWA. Oberflächensprache **Deutsch**.
|
|||||||
- **Dev-Umgebung**: Postgres auf `localhost:5439` (`docker-compose.dev.yml`),
|
- **Dev-Umgebung**: Postgres auf `localhost:5439` (`docker-compose.dev.yml`),
|
||||||
Dev-Server auf **Port 3011** (3000 und 3010 sind von anderen Projekten belegt).
|
Dev-Server auf **Port 3011** (3000 und 3010 sind von anderen Projekten belegt).
|
||||||
- **Screenshots**: `node scripts/shot.mjs <url> <ziel.png> [w] [h] [theme]`.
|
- **Screenshots**: `node scripts/shot.mjs <url> <ziel.png> [w] [h] [theme]`.
|
||||||
|
Achtung: das Skript meldet sich **nicht** an — bei geschützten Seiten entsteht
|
||||||
|
kommentarlos ein Bild der Anmeldemaske. Für angemeldete Ansichten den
|
||||||
|
Login-Weg aus `scripts/screenshots.mjs` nachbauen.
|
||||||
- Next hängt selbst einen Block an diese Datei an — der bleibt drin.
|
- Next hängt selbst einen Block an diese Datei an — der bleibt drin.
|
||||||
|
|
||||||
## Fortschritt
|
## Fortschritt
|
||||||
@@ -119,6 +122,18 @@ Statistiken, Benachrichtigungen, REST-API, PWA. Oberflächensprache **Deutsch**.
|
|||||||
das ASCII-Schlusszeichen beendet den String. In JSX-Text und Kommentaren ok.
|
das ASCII-Schlusszeichen beendet den String. In JSX-Text und Kommentaren ok.
|
||||||
- Heredocs im Bash-Tool sind bei langen TSX-Dateien unzuverlässig — dann das
|
- Heredocs im Bash-Tool sind bei langen TSX-Dateien unzuverlässig — dann das
|
||||||
Write-Werkzeug benutzen.
|
Write-Werkzeug benutzen.
|
||||||
|
- **Klickwege niemals gegen `npm run dev` prüfen.** Unter headless Chromium
|
||||||
|
scheitert der HMR-Socket (`ERR_INVALID_HTTP_RESPONSE`), dadurch hydratisiert
|
||||||
|
**keine** Seite und kein Knopf reagiert — ohne Seitenfehler, ohne
|
||||||
|
fehlgeschlagene Anfrage, es passiert einfach nichts. Sieht aus wie ein Fehler
|
||||||
|
im eigenen Code, ist aber die Umgebung. Stattdessen
|
||||||
|
`npm run build` und `PORT=3012 npm start`, dann dagegen klicken.
|
||||||
|
Formulare täuschen zusätzlich: die Anmeldung funktioniert auch ohne
|
||||||
|
JavaScript, wirkt also intakt.
|
||||||
|
- Vor `npm start` prüfen, ob der Port noch von einem früheren Lauf belegt ist —
|
||||||
|
sonst startet der neue Server gar nicht und man testet den alten Bau.
|
||||||
|
- Testdaten nach Klickproben wieder herstellen: die Proben schreiben in die
|
||||||
|
geseedete Entwicklungsdatenbank.
|
||||||
|
|
||||||
<!-- BEGIN:nextjs-agent-rules -->
|
<!-- BEGIN:nextjs-agent-rules -->
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ Ablauf: Datenbank sichern → Änderungen holen → Image bauen → neu starten
|
|||||||
warten, bis die Instanz wieder antwortet. Die Datenbankmigrationen spielt der
|
warten, bis die Instanz wieder antwortet. Die Datenbankmigrationen spielt der
|
||||||
Container beim Start selbst ein.
|
Container beim Start selbst ein.
|
||||||
|
|
||||||
|
Geprüft wird zuerst http://127.0.0.1:APP_PORT/api/health. Ist der Port gar
|
||||||
|
nicht auf dem Host veröffentlicht — üblich hinter einem Reverse Proxy —,
|
||||||
|
zählt stattdessen der Healthcheck des Containers.
|
||||||
|
|
||||||
Optionen:
|
Optionen:
|
||||||
--ohne-backup Keine Sicherung anlegen (nicht empfohlen)
|
--ohne-backup Keine Sicherung anlegen (nicht empfohlen)
|
||||||
--ohne-pull Nichts aus dem Repository holen, nur neu bauen und starten
|
--ohne-pull Nichts aus dem Repository holen, nur neu bauen und starten
|
||||||
@@ -196,31 +200,95 @@ gut "Container laufen."
|
|||||||
schritt "Auf die Instanz warten"
|
schritt "Auf die Instanz warten"
|
||||||
info "Die Datenbankmigrationen spielt der Container beim Start selbst ein."
|
info "Die Datenbankmigrationen spielt der Container beim Start selbst ein."
|
||||||
|
|
||||||
|
# Der Container meldet seinen Zustand selbst — der HEALTHCHECK im Image fragt
|
||||||
|
# /api/health von innen ab. Das ist der verlässlichere Weg: hinter einem
|
||||||
|
# Reverse Proxy ist der App-Port oft gar nicht auf dem Host veröffentlicht,
|
||||||
|
# und dann sagt ein fehlschlagendes curl nichts über die Instanz aus.
|
||||||
|
# Gibt immer 0 zurück: die Funktion läuft auch im Fehlerpfad, und unter
|
||||||
|
# `set -e` dürfte eine Auskunft über den Zustand nicht selbst das Skript
|
||||||
|
# abbrechen, bevor der Weg zurück ausgegeben wurde.
|
||||||
|
container_zustand() {
|
||||||
|
local id
|
||||||
|
id=$($COMPOSE ps -q app 2>/dev/null || true)
|
||||||
|
if [ -z "$id" ]; then
|
||||||
|
printf 'kein-container'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
# Ohne HEALTHCHECK im Image ist .State.Health leer — dann bleibt der
|
||||||
|
# Laufzustand (running/exited) als grobe Auskunft.
|
||||||
|
docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}ohne-healthcheck:{{.State.Status}}{{end}}' \
|
||||||
|
"$id" 2>/dev/null || printf 'unbekannt'
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
GESUND=0
|
GESUND=0
|
||||||
|
UEBER_CONTAINER=0
|
||||||
for _ in $(seq 1 60); do
|
for _ in $(seq 1 60); do
|
||||||
if curl -fsS "http://127.0.0.1:${PORT}/api/health" >/dev/null 2>&1; then
|
if curl -fsS "http://127.0.0.1:${PORT}/api/health" >/dev/null 2>&1; then
|
||||||
GESUND=1
|
GESUND=1
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
|
if [ "$(container_zustand)" = "healthy" ]; then
|
||||||
|
GESUND=1
|
||||||
|
UEBER_CONTAINER=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$GESUND" -eq 1 ]; then
|
if [ "$GESUND" -eq 1 ]; then
|
||||||
ANTWORT=$(curl -fsS "http://127.0.0.1:${PORT}/api/health" 2>/dev/null || true)
|
if [ "$UEBER_CONTAINER" -eq 1 ]; then
|
||||||
gut "Flimmer antwortet auf Port ${PORT}."
|
gut "Der Container meldet sich gesund."
|
||||||
leise "$ANTWORT"
|
leise "Auf Port ${PORT} war nichts zu erreichen — das ist normal, wenn die App"
|
||||||
|
leise "nur über einen Reverse Proxy erreichbar ist und den Port nicht veröffentlicht."
|
||||||
|
else
|
||||||
|
ANTWORT=$(curl -fsS "http://127.0.0.1:${PORT}/api/health" 2>/dev/null || true)
|
||||||
|
gut "Flimmer antwortet auf Port ${PORT}."
|
||||||
|
leise "$ANTWORT"
|
||||||
|
fi
|
||||||
|
|
||||||
printf '\n%s✓ Fertig — Version %s%s\n' "$GUT" "$NEUE_VERSION" "$AUS"
|
printf '\n%s✓ Fertig — Version %s%s\n' "$GUT" "$NEUE_VERSION" "$AUS"
|
||||||
if [ "$VORHER_VERSION" != "$NEUE_VERSION" ]; then
|
if [ "$VORHER_VERSION" != "$NEUE_VERSION" ]; then
|
||||||
info "Was sich geändert hat, steht in CHANGELOG.md."
|
info "Was sich geändert hat, steht in CHANGELOG.md."
|
||||||
fi
|
fi
|
||||||
[ -n "$SICHERUNG" ] && leise "Sicherung: $SICHERUNG"
|
if [ -n "$SICHERUNG" ]; then
|
||||||
|
leise "Sicherung: $SICHERUNG"
|
||||||
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Fehlschlag: konkreter Weg zurück ----------------------------------------
|
# --- Fehlschlag: konkreter Weg zurück ----------------------------------------
|
||||||
|
|
||||||
printf '\n%s✗ Die Instanz antwortet nach zwei Minuten nicht.%s\n\n' "$FEHLER" "$AUS" >&2
|
printf '\n%s✗ Die Instanz antwortet nach zwei Minuten nicht.%s\n\n' "$FEHLER" "$AUS" >&2
|
||||||
|
|
||||||
|
# Der Container-Zustand grenzt ein, wo es klemmt — ohne ihn sähe ein nicht
|
||||||
|
# veröffentlichter Port genauso aus wie eine abgestürzte App.
|
||||||
|
ZUSTAND=$(container_zustand)
|
||||||
|
case "$ZUSTAND" in
|
||||||
|
kein-container)
|
||||||
|
info "Es läuft gar kein app-Container. Der Start ist offenbar fehlgeschlagen."
|
||||||
|
;;
|
||||||
|
starting)
|
||||||
|
info "Der Container startet noch. Möglicherweise dauern die Migrationen länger —"
|
||||||
|
info "sieh im Log nach und gib ihm etwas Zeit."
|
||||||
|
;;
|
||||||
|
unhealthy)
|
||||||
|
info "Der Container läuft, meldet sich aber als nicht gesund. Der Fehler liegt"
|
||||||
|
info "also in der Anwendung, nicht am Port."
|
||||||
|
;;
|
||||||
|
ohne-healthcheck:running)
|
||||||
|
info "Der Container läuft, das Image bringt aber keinen Healthcheck mit (ältere"
|
||||||
|
info "Fassung). Ob die App wirklich antwortet, verrät nur das Log."
|
||||||
|
;;
|
||||||
|
ohne-healthcheck:*)
|
||||||
|
info "Der Container ist nicht gelaufen: ${ZUSTAND#ohne-healthcheck:}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
info "Container-Zustand: ${ZUSTAND}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
printf '\n'
|
||||||
|
|
||||||
info "Log ansehen:"
|
info "Log ansehen:"
|
||||||
printf ' %s logs --tail 50 app\n\n' "$COMPOSE"
|
printf ' %s logs --tail 50 app\n\n' "$COMPOSE"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user