Zwei Fehler im neuen Deploy-Weg, beide bei einem Testlauf gefunden.
1. Das Skript uebersprang den Build, wenn vorher von Hand git pull lief.
Die Entscheidung haengte an HEAD vs. origin/main -- nach einem manuellen
Pull sind beide gleich, also "Nothing to do", obwohl der vorhandene Build
aus einem aelteren Commit stammte. Genau das ist beim Deploy von v1.120.0
passiert: gepullt wurde, gebaut nicht, ausgeliefert blieb 1.119.4.
Massgeblich ist jetzt .next/BUILD_COMMIT.
Mein Rat, vor dem Skript git pull auszufuehren, hat den Fall ueberhaupt
erst ausgeloest -- das Skript pullt selbst.
2. Der Smoke-Test-Server ueberlebte das Beenden. ( ... ) & startet eine
Subshell, $! ist deren PID; node lief als Waise weiter und hielt Port
3999 belegt. Jeder weitere Deploy waere daran gescheitert. exec ersetzt
die Subshell, kill greift, kill -9 fasst nach, der ERR-Trap raeumt
ebenfalls auf, und vorab wird geprueft ob der Port frei ist.
Beide Szenarien getestet: alter Build wird erkannt und neu gebaut,
gleicher Stand wird uebersprungen, Port bleibt frei.
v1.120.1
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Der Wert 2048 aus v1.119.3 stammte aus der Zeit, als der Container 3 GB
hatte. Er war zu niedrig gewaehlt: Der Build starb punktgenau bei 2045 MB,
also an meiner eigenen Grenze. Gemessener Bedarf sind rund 2,6 GB, deshalb
jetzt 4096. Der Container hat inzwischen 6 GB und damit genug Luft.
v1.119.4
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Deploy starb mit "Ineffective mark-compacts near heap limit". Nodes
Standard-Heap richtet sich nach dem Arbeitsspeicher und liegt auf dem
Container bei rund 1,5 GB -- zu wenig fuer next build. update-app.sh setzt
jetzt --max-old-space-size=2048.
Ich hatte zuerst ESLint im Build verdaechtigt (mein ignoreDuringBuilds:
false aus v1.117.4) und die Aenderung zurueckgenommen. Eine Messung
widerlegte das: Spitzenspeicher mit ESLint 2.590 MB, ohne 2.595 MB -- kein
Unterschied. Die Ruecknahme ist damit hinfaellig, ESLint bleibt im Build.
Der Build braucht rund 2,6 GB. Bei 3 GB Container-RAM bleibt das knapp;
NODE_OPTIONS ist die Sofortmassnahme, mehr RAM fuer LXC 202 die eigentliche
Loesung. Steht als Block J in TODO.md, zusammen mit der Alternative, den
Build auf den Spark zu verlagern.
v1.119.3
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There were two near-identical update scripts and they drifted: the npm ci fix
from 1.114.1 only ever landed in update-app.sh, so the boot path kept running
npm install. my-weekly-todo-update.service now runs update-app.sh, and
boot-update.sh is a shim kept only so a not-yet-recopied unit still works.
To be usable at boot the script needed three things it did not have:
- Skip the rebuild when HEAD already matches origin/main and a standalone
build exists, so a reboot is not a full rebuild every time (--force
overrides).
- Do not restart PM2 when its daemon is not up yet. At boot this unit runs
before pm2-root.service, and probing with `pm2 describe` would spawn a
stray daemon that races the real service, so it checks the pid file.
- A flock single-instance lock, so a boot run and a manual run cannot install
into the same tree at once.
It also picks up prisma migrate deploy / generate and the .env copy that only
the boot script had. The log moved to /var/log/my-weekly-todo-update.log.
v1.115.2
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
next.config.js sets output: 'standalone', but Next.js does not copy public/
or .next/static/ into .next/standalone — that is a documented manual step.
Skipping it shipped new server code referencing new chunk hashes while the
old chunks stayed in the standalone tree, so those requests 404'd, React
never hydrated, and pages hung on "Loading session..." while the API kept
returning 200.
v1.114.2
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Moves the deploy script off the server and into the repo as
scripts/update-app.sh, with the two fixes made during the v1.114.0 deploy:
- set -euo pipefail, so a failed git pull aborts instead of rebuilding and
restarting PM2 on unchanged code while printing "Update Complete"
- npm ci instead of npm install, which rewrote package-lock.json and left the
tree dirty so the next git pull aborted
The body is wrapped in a main() function because the script lives inside the
checkout it updates, and git pull rewriting it mid-run would leave bash
reading from a stale file offset.
v1.114.1
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>