Files
pdf-ocr-hotfolder/docs/OS-UPGRADE.md
T
techadmin 3e24aa2ecd feat: Wiederaufnahme aus working/, --check-config, feldtauglicher Updater (v0.6.0)
Datenverlust behoben:
- Nach hartem Stopp blieb das Original in working/ liegen und wurde nie
  wieder angefasst (_scan_existing sah nur incoming/). Es wird jetzt beim
  Start an Ort und Stelle wieder aufgegriffen, mit Kollisionsschutz gegen
  gleichnamige neue Scans; angefangene __ocr_-Fragmente werden geloescht.
- TimeoutStopSec 30 -> 300, damit laufendes OCR zu Ende laufen darf.

Config-Drift sichtbar gemacht:
- Neues --check-config (Exit 0 sauber / 1 Warnungen / 2 Fehler), das
  update.sh vor dem Neustart ueber alle Instanz-Configs laufen laesst.
- Warnungen fuer [ocr].timeout >= 900 (seit 0.4.0 pro SEITE) und gesetztes
  pdfa_level, beim Dienststart wie im Check.
- Unbekannte Config-Keys werden nicht mehr still verworfen, sondern genannt.

Updater feldtauglich:
- venv-Health-Check erkennt toten Symlink UND Versions-Drift gegen das
  System-Python; --rebuild-venv als ausdruecklicher Weg nach einem Debian-
  Major-Upgrade. Neubau ist ganz-oder-gar-nicht mit Rollback.
- apt-Pakete werden auch beim Update synchronisiert (Quelle: install.sh).
- Instanz-Erfassung inkl. activating/failed, Verifikation prueft is-failed
  und NRestarts statt sleep 1 + is-active.
- Backup enthaelt Configs, Unit, Drop-ins und pip-freeze.txt, liegt auf
  0600 und rotiert auf 5; schlaegt es fehl, bricht das Update vorher ab.
- ERR-Trap faehrt die vorher laufenden Instanzen wieder hoch.
- lxc-compat.conf wird beim Update nachgezogen.
- requirements.txt gepinnt (ocrmypdf 16.13.0, geprueft fuer Python 3.11+3.13).

Doku in Installation / Update / OS-Upgrade aufgeteilt (docs/).
135 Tests gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 22:04:04 +02:00

6.8 KiB

Debian-Major-Upgrade

Wie der Hotfolder ein Distributions-Upgrade übersteht (12 → 13, später 13 → 14).

Verwandte Dokumente: README · Installation · Update


Warum das ein eigener Ablauf ist

Die venv unter /opt/pdf-ocr-hotfolder/venv/ hängt an der Python-Version der Distribution. Ein apt full-upgrade von Debian 12 auf 13 tauscht Python 3.11 gegen 3.13 aus. Danach zeigt venv/bin/python auf einen Interpreter, den es so nicht mehr gibt — systemd quittiert den Start jeder Instanz mit 203/EXEC, und auch wenn der Interpreter noch existiert, passen die installierten Pakete nicht mehr zum System-Python.

Die venv muss nach dem Sprung neu gebaut werden. Ein normales sudo ./update.sh genügt dafür nicht sicher genug — es gibt den ausdrücklichen Schalter --rebuild-venv.


Der Ablauf

1. Vorher updaten

cd /pfad/zum/repo
git pull
sudo ./update.sh

Das bringt die Installation auf den aktuellen Stand und erzeugt vor allem ein frisches Backup inklusive pip-freeze.txt — die Liste der Paketversionen, die auf dem alten System liefen. Inhalt und Ort des Backups: UPDATE.md.

2. Instanzen stoppen

sudo systemctl stop 'pdf-ocr-hotfolder@*'

Während des Upgrades darf kein OCR laufen: Ghostscript, Tesseract und die Python-Pakete werden mitten im Betrieb ausgetauscht.

Geduld. Die Unit hat TimeoutStopSec=300, damit ein laufendes OCR sauber zu Ende kommt. Ein Stop kann pro Instanz bis zu 5 Minuten dauern — bei mehreren Instanzen entsprechend länger. Nicht mit kill -9 nachhelfen; ein harter Stopp lässt das Original in working/ liegen (der Dienst nimmt es beim nächsten Start zwar wieder auf, aber der Durchlauf ist verloren).

Prüfen, dass wirklich alles steht:

systemctl status 'pdf-ocr-hotfolder@*'

3. Distribution upgraden

Der übliche Debian-Weg — Sources auf das neue Release umstellen, dann:

sudo apt update
sudo apt full-upgrade
sudo reboot

Die Instanzen sind enabled und starten nach dem Reboot mit; mit der alten venv scheitern sie (203/EXEC). Das ist erwartet und wird im nächsten Schritt behoben.

4. venv neu bauen

cd /pfad/zum/repo
git pull
sudo ./update.sh --rebuild-venv

--rebuild-venv erzwingt den Neubau. Der Rest des Updates läuft wie gewohnt (siehe UPDATE.md) — die System-Pakete werden dabei ebenfalls abgeglichen, auch python3-venv für das neue Python.

Der Neubau ist ganz oder gar nicht:

  1. Die alte venv wird nach venv.old-<timestamp> verschoben.
  2. python3 -m venv baut neu.
  3. Die Requirements werden installiert.
  4. Erst bei Erfolg wird die alte venv gelöscht.

5. Wenn ein Pin nicht mehr passt

Scheitert pip install an einer gepinnten Version, bricht das Skript ab und sagt genau, was los ist:

  • die letzten 25 Zeilen der pip-Ausgabe,
  • das gescheiterte Paket ("Gescheitertes Paket: …"),
  • die Diagnose: "eine in requirements.txt fest gepinnte Version gibt es für Python <version> nicht (mehr)",
  • den nächsten Schritt: requirements.txt anheben und update.sh --rebuild-venv erneut laufen lassen.

Die alte venv ist dann zurückgerollt — es liegt keine halb gefüllte venv herum. Sie hängt zwar weiterhin am alten Interpreter und die Instanzen laufen damit nicht (das sagt das Skript auch), aber der Zustand ist eindeutig.

Also:

# im Repo, auf einer Testmaschine
vim requirements.txt          # Version des genannten Pakets anheben
pytest                        # Suite muss grün bleiben
git commit -am 'requirements: <paket> auf <version> anheben'
git push

# auf dem Zielsystem
git pull
sudo ./update.sh --rebuild-venv

6. --rebuild-venv vergessen?

Halb so wild: update.sh prüft die venv auch ohne den Schalter und baut sie bei Versions-Drift von selbst neu. Geprüft wird

  • ob das Verzeichnis und venv/bin/python überhaupt existieren,
  • ob der Interpreter der venv noch läuft (toter Symlink nach dem Upgrade),
  • ob seine major.minor zum System-python3 passt,
  • ob pyvenv.cfg dieselbe Version nennt wie der Interpreter.

Stimmt eines davon nicht, nennt das Skript den Grund und baut neu. --rebuild-venv ist also nicht der einzige, aber der ausdrückliche Weg — und der, den man nach einem Distributions-Upgrade nimmt, statt sich auf die Erkennung zu verlassen.


Danach prüfen

Laufen alle Instanzen?

systemctl status 'pdf-ocr-hotfolder@*'

update.sh hat das schon verifiziert (Wartezeit, is-failed, Crash-Loop) und in der Zusammenfassung Soll gegen Ist gestellt — ein Exit 0 heißt, dass jede Instanz, die vorher lief, auch wieder läuft.

Sind die Configs sauber?

for f in /etc/pdf-ocr-hotfolder/*.toml; do
    sudo /opt/pdf-ocr-hotfolder/venv/bin/python -m pdf_ocr_hotfolder \
        --check-config --config "$f"
done

Exit 0/1/2 und was bei Warnungen zu tun ist: UPDATE.md.

Läuft eine echte PDF durch?

cp test.pdf /var/lib/pdf-ocr-hotfolder/<instanz>/incoming/
journalctl -u pdf-ocr-hotfolder@<instanz> -f

Im outgoing/ muss das OCR-PDF liegen, im Journal steht OCR done. Das ist der einzige Test, der die neue venv und die neuen System-Binaries (Tesseract, Ghostscript) wirklich anfasst — systemctl status sagt darüber nichts.

Ghostscript-Version auf dem neuen Release ansehen:

gs --version

Auf Debian 13 ist der Ghostscript-Bug aus Debian 12 kein Thema mehr; ein bookworm-backports-Eintrag unter /etc/apt/sources.list.d/ gehört nach dem Upgrade entfernt. Hintergrund: INSTALLATION.md.


Pins in requirements.txt

Die Python-Abhängigkeiten sind bewusst fest gepinnt:

ocrmypdf==16.13.0
watchdog==6.0.0
requests==2.33.1
paramiko==4.0.0

Ohne Pins würde ein pip install --upgrade bei jedem Update ungefragt eine neue Major-Version ziehen — ein Sprung von ocrmypdf 16 auf 17 reißt sonst alle Instanzen auf einmal, und zwar im Moment des Updates, nicht zu einem Zeitpunkt, den man sich ausgesucht hat.

Die aktuellen Pins sind gegen Python 3.11 (Debian 12) und 3.13 (Debian 13) geprüft; für beide gibt es fertige Wheels, es wird nichts kompiliert.

Beim Anheben:

  1. Testmaschine benutzen — nie direkt auf dem produktiven Hotfolder.
  2. Dort update.sh --rebuild-venv fahren, damit die Pakete wirklich frisch aufgelöst werden.
  3. pytest muss grün bleiben (135 Tests).
  4. Eine echte PDF durchschieben — die Test-Suite mockt ocrmypdf, ein Major-Sprung fällt dort also nicht auf.
  5. Erst dann committen und auf die produktiven Systeme geben.

Der ocrmypdf-Sprung 16 → 17 ist ein Major-Sprung und gehört in einen eigenen Vorgang mit eigenem Test, nicht in ein OS-Upgrade.