feat: fehlgeschlagener Build reisst die laufende App nicht mehr mit
next build lief direkt auf .next -- also auf dem Verzeichnis, aus dem die laufende Instanz bedient wird. Brach der Build ab, fand PM2 server.js nicht mehr (MODULE_NOT_FOUND) und geriet in eine Neustartschleife mit ueber 790 Versuchen. Am 07.09. war die Seite dadurch rund eine Stunde unbrauchbar. Neuer Ablauf: 1. Build nach .next-build, .next bleibt unangetastet 2. statische Dateien und .env in den neuen Baum 3. Smoke-Test: der neue Build wird auf Port 3999 gestartet und muss auf /auth/login antworten -- ein Build kann durchlaufen und trotzdem nicht starten 4. erst danach umschalten, alter Stand bleibt als .next-previous liegen 5. PM2 neu starten Scheitert etwas davon, raeumt der ERR-Trap .next-build weg und die laufende App bleibt unveraendert. Die Meldung "die laufende App bleibt unberuehrt" stimmt damit endlich -- vorher war sie schlicht falsch. Geprueft wurde vorher, dass der umbenannte Build ueberhaupt startet: der standalone-Ausgabebaum traegt den distDir-Namen intern, server.js findet seine Dateien aber relativ zu sich selbst. Testweise gestartet, Login-Seite und JS-Dateien lieferten 200. Beide Faelle durchgespielt: Abbruch liess .next samt Markierung unberuehrt und raeumte .next-build weg; Erfolg schaltete um, legte .next-previous an und bestand den Smoke-Test. v1.120.0 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
bea9723a6f
commit
162c56d0d3
4
.gitignore
vendored
4
.gitignore
vendored
@ -60,3 +60,7 @@ INFRASTRUCTURE_REQUIREMENTS.md
|
||||
# feste Namen, weshalb .env.production.save durchs Raster fiel
|
||||
.env*
|
||||
!.env.example
|
||||
|
||||
# Build-Arbeitsverzeichnisse von scripts/update-app.sh
|
||||
.next-build/
|
||||
.next-previous/
|
||||
|
||||
25
CHANGELOG.md
25
CHANGELOG.md
@ -2,6 +2,31 @@
|
||||
|
||||
All notable changes to this project are documented in this file.
|
||||
|
||||
## [1.120.0] - 2026-09-07
|
||||
|
||||
### Changed
|
||||
- **Ein fehlgeschlagener Build reisst die laufende App nicht mehr mit.** `next build` lief
|
||||
bisher direkt auf `.next` — also auf dem Verzeichnis, aus dem die laufende Instanz bedient
|
||||
wird. Brach der Build ab, fand PM2 `server.js` nicht mehr (`MODULE_NOT_FOUND`) und geriet
|
||||
in eine Neustartschleife; am 07.09. war die Seite deshalb rund eine Stunde unbrauchbar.
|
||||
|
||||
Der neue Ablauf in `scripts/update-app.sh`:
|
||||
1. Build nach `.next-build` — `.next` bleibt dabei unangetastet
|
||||
2. Statische Dateien und `.env` in den neuen Baum kopieren
|
||||
3. **Smoke-Test:** Der neue Build wird auf Port 3999 gestartet und muss auf
|
||||
`/auth/login` antworten. Ein Build kann durchlaufen und trotzdem nicht starten.
|
||||
4. Erst danach umschalten; der alte Stand bleibt als `.next-previous` liegen
|
||||
5. PM2 neu starten
|
||||
|
||||
Scheitert irgendetwas davon, wird `.next-build` weggeräumt und die laufende App bleibt
|
||||
unverändert. Zum Zurückrollen genügt `mv .next-previous .next` plus PM2-Neustart.
|
||||
|
||||
- `next.config.js`: `distDir` kommt jetzt aus `NEXT_DIST_DIR` und fällt auf `.next` zurück.
|
||||
|
||||
Beide Fälle sind praktisch getestet: Ein abgebrochener Lauf liess `.next` samt Markierung
|
||||
unberührt und räumte `.next-build` weg; ein erfolgreicher schaltete sauber um, legte
|
||||
`.next-previous` an und bestand den Smoke-Test.
|
||||
|
||||
## [1.119.4] - 2026-09-07
|
||||
|
||||
### Fixed
|
||||
|
||||
29
TODO.md
29
TODO.md
@ -286,6 +286,31 @@ Umgestellt auf `dataSources.query()`; die Suche filtert jetzt auf `data_source`
|
||||
|
||||
---
|
||||
|
||||
## Block K — Deploy-Sicherheit ✅
|
||||
|
||||
### K1. Build zerstört nicht mehr die laufende App ✅ *(v1.120.0)*
|
||||
- [x] Build läuft nach `.next-build`, das laufende `.next` bleibt unberührt
|
||||
- [x] Smoke-Test vor dem Umschalten — der neue Build muss einmal geantwortet haben
|
||||
- [x] Umschalten erst danach, alter Stand bleibt als `.next-previous` liegen
|
||||
- [x] Beide Fälle getestet: Fehlschlag lässt `.next` unangetastet, Erfolg schaltet sauber um
|
||||
|
||||
**Warum:** `next build` lief direkt auf `.next` — also auf dem Verzeichnis, aus dem die
|
||||
laufende App bedient wird. Scheiterte der Build, war nicht nur das Update weg, sondern die
|
||||
laufende Instanz gleich mit: PM2 fand `server.js` nicht mehr
|
||||
(`MODULE_NOT_FOUND`) und geriet in eine Neustartschleife mit über 790 Versuchen.
|
||||
Am 07.09. war die Seite dadurch rund eine Stunde unbrauchbar.
|
||||
|
||||
**Zurückrollen** (falls ein Deploy doch mal Mist ausliefert):
|
||||
|
||||
```bash
|
||||
pm2 stop my-weekly-todo
|
||||
cd /root/My-Weekly-ToDo-List
|
||||
rm -rf .next && mv .next-previous .next
|
||||
pm2 restart my-weekly-todo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Block J — Build-Speicher auf dem Container
|
||||
|
||||
### J1. Container-RAM erhöhen *(empfohlen)*
|
||||
@ -316,7 +341,7 @@ Deploy-Wegs, aber die sauberste Trennung.
|
||||
|
||||
## Block I — UI-Wünsche
|
||||
|
||||
### I1. Aktuellen Tag auch im Spaltenkopf hervorheben *(erledigt, bitte ansehen)*
|
||||
### I1. Aktuellen Tag auch im Spaltenkopf hervorheben ✅ *(vom Nutzer bestätigt)*
|
||||
- [x] Hervorhebungsfarbe zusätzlich hinter Wochentagsname und Datum gelegt
|
||||
|
||||
**Wunsch:** Der laufende Tag soll deutlicher auffallen. Aktuell ist nur der Spaltenkörper
|
||||
@ -331,7 +356,7 @@ offenbar mit eigenem Hintergrund. Der Wochentagsname hat bereits eine eigene Reg
|
||||
**Zu klären:** Der Kopf ist vermutlich `sticky` und braucht deshalb einen deckenden
|
||||
Hintergrund — die Farbe muss also gesetzt, nicht nur geerbt werden.
|
||||
|
||||
### I2. Symbole in Kalenderterminen nach oben rechts *(erledigt, bitte ansehen)*
|
||||
### I2. Symbole in Kalenderterminen nach oben rechts ✅ *(vom Nutzer bestätigt, Freiraum reicht)*
|
||||
- [x] `.event-icons-row` nach oben rechts verschoben, Titel bekommt rechts Freiraum
|
||||
|
||||
**Wunsch:** Die kleinen Symbole (Wiederholung, Anbieter) sitzen unten rechts im Termin und
|
||||
|
||||
@ -3,6 +3,10 @@ const { version } = require('./package.json');
|
||||
|
||||
const nextConfig = {
|
||||
output: 'standalone',
|
||||
// Ziel des Builds. update-app.sh baut nach .next-build, damit das laufende .next
|
||||
// waehrend des Builds unberuehrt bleibt, und schaltet erst nach erfolgreichem
|
||||
// Smoke-Test um. Ohne das zerstoert ein fehlgeschlagener Build die laufende App.
|
||||
distDir: process.env.NEXT_DIST_DIR || '.next',
|
||||
eslint: {
|
||||
// Aus: Der Build meldet ESLint-Fehler. Warnungen blockieren ihn nicht, nur Errors.
|
||||
//
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.119.4",
|
||||
"version": "1.120.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.119.4",
|
||||
"version": "1.120.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "^2.11.1",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.119.4",
|
||||
"version": "1.120.0",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -34,7 +34,10 @@ main() {
|
||||
|
||||
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"; }
|
||||
|
||||
trap 'log "!!! Update FAILED at line $LINENO (exit $?) — the running build is untouched"' ERR
|
||||
# Bei einem Abbruch den halbfertigen Build wegraeumen. Der Hinweis "die laufende App
|
||||
# bleibt unberuehrt" stimmt seit v1.120.0 tatsaechlich -- vorher wurde direkt auf .next
|
||||
# gebaut, ein Fehlschlag riss die laufende Instanz mit.
|
||||
trap 'log "!!! Update FAILED at line $LINENO (exit $?) — die laufende App bleibt unberuehrt"; rm -rf "${APP_DIR:-.}/.next-build"' ERR
|
||||
|
||||
# Fail fast instead of hanging on a credential prompt when run without a terminal
|
||||
# (systemd has no tty). The host authenticates via a read-only SSH deploy key.
|
||||
@ -95,24 +98,82 @@ main() {
|
||||
log "--- Regenerating Prisma client ---"
|
||||
npx prisma generate
|
||||
|
||||
# Der Standard-Heap von Node richtet sich nach dem Arbeitsspeicher und lag auf diesem
|
||||
# Container bei rund 1,5 GB -- zu wenig fuer `next build`. Ein erster Versuch mit 2048
|
||||
# scheiterte ebenfalls: der Build starb punktgenau bei 2045 MB. Gemessener Bedarf sind
|
||||
# rund 2,6 GB, deshalb 4 GB. Der Container hat 6 GB, das laesst genug Luft fuer den
|
||||
# laufenden PM2-Prozess.
|
||||
log "--- Building application ---"
|
||||
NODE_OPTIONS="--max-old-space-size=4096" npm run build
|
||||
# ── Build in ein Nebenverzeichnis ────────────────────────────────────────────────
|
||||
#
|
||||
# Frueher lief `next build` direkt auf .next -- also auf dem Verzeichnis, aus dem die
|
||||
# laufende App bedient wird. Scheiterte der Build, war nicht nur das Update weg, sondern
|
||||
# die laufende Instanz gleich mit: PM2 fand server.js nicht mehr und geriet in eine
|
||||
# Neustartschleife. Genau das ist am 07.09. passiert, die Seite war rund eine Stunde
|
||||
# unbrauchbar.
|
||||
#
|
||||
# Jetzt entsteht der neue Build unter .next-build. Das laufende .next wird dabei nicht
|
||||
# angefasst. Erst wenn der neue Build gebaut UND probeweise gestartet werden konnte,
|
||||
# wird umgeschaltet.
|
||||
#
|
||||
# Nodes Standard-Heap lag hier bei rund 1,5 GB und reichte nicht; ein Versuch mit 2048
|
||||
# scheiterte punktgenau bei 2045 MB. Gemessener Bedarf sind rund 2,6 GB.
|
||||
local BUILD_DIR=".next-build"
|
||||
rm -rf "$BUILD_DIR"
|
||||
|
||||
# next.config.js sets output: 'standalone', and Next.js does NOT copy public/ or
|
||||
# .next/static/ into .next/standalone — that is a documented manual step. Skipping it
|
||||
# ships new server code whose HTML references new chunk hashes while the old chunks sit
|
||||
# in the standalone tree: they 404, React never hydrates, and every page hangs on its
|
||||
# server-rendered shell ("Loading session...") while the API still answers 200.
|
||||
log "--- Building application (nach $BUILD_DIR) ---"
|
||||
NEXT_DIST_DIR="$BUILD_DIR" NODE_OPTIONS="--max-old-space-size=4096" npm run build
|
||||
|
||||
# next.config.js setzt output: 'standalone', und Next.js kopiert public/ und static/
|
||||
# NICHT selbst dorthin -- ein dokumentierter manueller Schritt. Wird er ausgelassen,
|
||||
# verweist das neue HTML auf Chunks, die im standalone-Baum fehlen: sie liefern 404,
|
||||
# React hydriert nie, und jede Seite haengt auf "Loading session...", waehrend die API
|
||||
# weiter 200 antwortet.
|
||||
#
|
||||
# Der innere Ordner traegt den Namen des distDir -- deshalb .next-build/static und nicht
|
||||
# .next/static. Beim Umschalten wandert er unveraendert mit; server.js findet ihn
|
||||
# relativ zu sich selbst (geprueft).
|
||||
log "--- Copying static assets into standalone output ---"
|
||||
cp -r public .next/standalone/
|
||||
mkdir -p .next/standalone/.next/static
|
||||
cp -r .next/static .next/standalone/.next/
|
||||
cp .env .next/standalone/ 2>/dev/null || true
|
||||
cp -r public "$BUILD_DIR/standalone/"
|
||||
mkdir -p "$BUILD_DIR/standalone/$BUILD_DIR/static"
|
||||
cp -r "$BUILD_DIR/static/." "$BUILD_DIR/standalone/$BUILD_DIR/static/"
|
||||
cp .env "$BUILD_DIR/standalone/" 2>/dev/null || true
|
||||
|
||||
# ── Smoke-Test auf einem freien Port ─────────────────────────────────────────────
|
||||
#
|
||||
# Ein Build kann durchlaufen und trotzdem nicht starten. Bevor der neue Stand live
|
||||
# geht, muss er einmal wirklich geantwortet haben.
|
||||
log "--- Smoke-Test des neuen Builds ---"
|
||||
local SMOKE_PORT=3999
|
||||
( cd "$BUILD_DIR/standalone" && PORT=$SMOKE_PORT node server.js > /tmp/smoke-test.log 2>&1 ) &
|
||||
local SMOKE_PID=$!
|
||||
local SMOKE_OK=0
|
||||
for _ in $(seq 1 20); do
|
||||
sleep 1
|
||||
if curl -sf -o /dev/null --max-time 3 "http://127.0.0.1:$SMOKE_PORT/auth/login"; then
|
||||
SMOKE_OK=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
kill "$SMOKE_PID" 2>/dev/null || true
|
||||
wait "$SMOKE_PID" 2>/dev/null || true
|
||||
|
||||
if [ "$SMOKE_OK" -ne 1 ]; then
|
||||
log "!!! Smoke-Test fehlgeschlagen -- der neue Build antwortet nicht."
|
||||
log " Die laufende App bleibt unveraendert. Ausgabe:"
|
||||
tail -20 /tmp/smoke-test.log | sed 's/^/ /'
|
||||
rm -rf "$BUILD_DIR"
|
||||
return 1
|
||||
fi
|
||||
log " Smoke-Test bestanden."
|
||||
|
||||
# ── Umschalten ───────────────────────────────────────────────────────────────────
|
||||
#
|
||||
# Ab hier ist der neue Build erwiesenermassen lauffaehig. Der alte bleibt als
|
||||
# .next-previous liegen; zum Zurueckrollen genuegt:
|
||||
# pm2 stop my-weekly-todo
|
||||
# rm -rf .next && mv .next-previous .next
|
||||
# pm2 restart my-weekly-todo
|
||||
log "--- Umschalten auf den neuen Build ---"
|
||||
rm -rf .next-previous
|
||||
if [ -d .next ]; then
|
||||
mv .next .next-previous
|
||||
fi
|
||||
mv "$BUILD_DIR" .next
|
||||
|
||||
# At boot this script runs before pm2-root.service, so the PM2 daemon is not up yet and
|
||||
# there is nothing to restart — pm2-root.service resurrects the app right after. Probing
|
||||
|
||||
Loading…
Reference in New Issue
Block a user