2 Commits

Author SHA1 Message Date
techadmin 305454eeb5 docs: Systemanforderungen und journald-Abhaengigkeit dokumentieren (v0.6.3)
Aus den Testlaeufen auf Debian 12 (CT 200) und Debian 13 (CT 201):

- Systemanforderungen: mindestens 2 GB RAM. Eine einzelne A4-Seite in
  300 dpi mit deskew=true hat auf einem 512-MB-Container den OOM-Killer
  ausgeloest (anon-rss:489676kB). Dazu der Zusammenhang RAM <->
  max_workers x jobs x Aufloesung, wie sich ein OOM-Kill aeussert und wie
  man ihn nachweist (/sys/fs/cgroup/memory.events, dmesg auf dem Host).
- Troubleshooting: kaputtes systemd-journald ist ein blinder Fleck, weil
  der Dienst seit v0.4.1 nur dorthin loggt. Symptom, erste Pruefung und
  ein Vordergrund-Notbehelf. Auf einem von zwei Testcontainern aufgetreten
  — kein generelles LXC-Muster.

Nebenbei korrigiert: toter Anker in docs/INSTALLATION.md (#3-ocr-sprachen
-> #4-ocr-sprachen) und eine veraltete Stelle im Briefing, die
requirements.txt noch als "ocrmypdf 16.x" beschrieb.

Reine Doku-Version, 152 Tests unveraendert gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 00:18:45 +02:00
techadmin 04dc3c7b72 fix: gedrucktem --check-config-Befehl fehlte das cd ins Installationsverzeichnis (v0.6.2)
Das Paket ist nicht pip-installiert, sondern liegt unter /opt/pdf-ocr-hotfolder
und wird nur ueber das Arbeitsverzeichnis gefunden. Der Hinweis, den update.sh
in der Zusammenfassung ausgibt, lief deshalb so wie gedruckt nicht
("No module named pdf_ocr_hotfolder"). Gleiches galt fuer die Beispiele in
README.md, docs/INSTALLATION.md, docs/UPDATE.md und docs/OS-UPGRADE.md.

Gefunden beim Update-Test v0.3.1 -> v0.6.1 auf CT 200 (Debian 12).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 23:05:29 +02:00
9 changed files with 221 additions and 14 deletions
+3 -3
View File
@@ -1,7 +1,7 @@
# AI Agent Briefing — PDF OCR Hotfolder
**Zuletzt aktualisiert:** 2026-09-22
**Version:** 0.6.1
**Zuletzt aktualisiert:** 2026-09-23
**Version:** 0.6.3
**Status:** Multi-Instanz-Betrieb, Preflight-Checks, Fehlerzählung, Wiederaufnahme aus `working/` und ein abgesicherter Updater (venv-Rebuild, Backup, Verifikation, Versionssprung-Meldung, Rauchtest). Test-Suite grün (152 pytest-Tests). Ein Produktiv-Einsatz ist im Repo (README/CHANGELOG) nicht dokumentiert — die bisherigen Fixes stammen aus Issues #1–#6 und aus Vorbereitungen auf Debian 13, nicht aus einem belegten Dauerbetrieb.
> **Betriebsabläufe stehen nicht hier**, sondern in:
@@ -50,7 +50,7 @@ pdf-ocr-hotfolder/
├── config.example.toml
├── install.sh # Interaktiver Installer + Instanz-Manager
├── update.sh # Updater (--help, --rebuild-venv), ~860 Zeilen
├── requirements.txt # feste Pins (ocrmypdf 16.x!)
├── requirements.txt # feste Pins (ocrmypdf 17.x — 16.x ist unbrauchbar, s. 0.6.1)
├── VERSION
├── CHANGELOG.md
├── README.md
+65
View File
@@ -1,5 +1,70 @@
# Changelog
## [0.6.3] - 2026-09-23
Reine Doku-Version — kein Code, kein Installer, kein Updater, keine Unit, keine
Tests angefasst (ausser dem Versionsstring). Beide Erkenntnisse stammen aus den
Testlaeufen auf Debian 12 und Debian 13.
### Added
- **Abschnitt "Systemanforderungen" in `docs/INSTALLATION.md`.** Die
Dimensionierung fehlte bisher komplett. Empfohlen werden **mindestens 2 GB
RAM**; 512 MB reichen fuer 300-dpi-Scans nachweislich nicht. Gemessen auf
einem LXC-Container mit 512 MB RAM + 512 MB Swap, Debian 13,
Ghostscript 10.05.1: eine **einzelne A4-Seite in 300 dpi** mit
`deskew = true` riss das cgroup-Limit und der Dienst wurde vom OOM-Killer
beendet (`oom-kill:constraint=CONSTRAINT_MEMCG, oom_memcg=/lxc/201,
task=python`, `total-vm:1168764kB, anon-rss:489676kB`). Dieselbe
Verarbeitung mit einer kleineren Seite (850x1100 px) lief in ca. 19 s sauber
durch.
- Dokumentiert ist der Zusammenhang **RAM <-> `max_workers` x `jobs` x
Aufloesung**: `max_workers` (Default 2) laesst zwei solcher Seiten
gleichzeitig laufen, der Spitzenbedarf multipliziert sich entsprechend.
Wer knapp dimensioniert, zieht zuerst `max_workers` herunter.
- Dazu, **wie sich ein OOM-Kill aeussert** (Dienst weg bzw. von systemd neu
gestartet, `NRestarts` steigt, Abbruch mitten in der Datei ohne Traceback,
PDF bleibt in `working/` liegen) und **wie man ihn nachweist**
(`/sys/fs/cgroup/memory.events` im Container, `dmesg` auf dem LXC-Host).
Ohne diese Pruefung sieht der Fall wie ein Anwendungsfehler aus und man
sucht in ocrmypdf, Tesseract oder der Config.
- Mit dem Hinweis, dass die Wiederaufnahme aus `working/` seit v0.6.0 den
Datenverlust abfaengt — der OOM selbst bleibt aber ein Problem: bei
unveraenderter Dimensionierung laeuft dieselbe Datei nach dem Neustart
erneut hinein.
- `README.md` bekommt im Schnellstart nur einen Einzeiler mit Verweis, keine
Dublette.
- **Troubleshooting-Eintrag "Keine Logs: No journal files were found" in
`docs/INSTALLATION.md`.** Auf einem der Testcontainer war
`systemd-journald.service` kaputt (`failed`, `status=243/CREDENTIALS`),
`journalctl` lieferte `No journal files were found.` Da der Dienst seit
v0.4.1 **ausschliesslich** nach journald loggt (kein FileHandler, kein
Logverzeichnis — bewusste Entscheidung), gibt es dann gar keine Dienstlogs:
ein blinder Fleck, der vor jeder Fehlersuche per
`systemctl status systemd-journald` auszuschliessen ist. Als Notbehelf ist
der Vordergrund-Aufruf dokumentiert
(`cd /opt/pdf-ocr-hotfolder && sudo -u pdfocr ./venv/bin/python -m
pdf_ocr_hotfolder --config ...`, das `cd` ist zwingend, s. 0.6.2).
Ausdruecklich festgehalten: das ist **kein** generelles LXC-Muster — der
zweite Testcontainer war in Ordnung, es war Schaden auf genau dieser
Maschine.
### Changed
- `AI_AGENT_BRIEFING.md`: der Kommentar zu `requirements.txt` in der
Projektstruktur nannte noch "ocrmypdf 16.x!" — genau die Version, die seit
0.6.1 als unbrauchbar gilt und gegen die der Pin schuetzt. Korrigiert auf
17.x.
## [0.6.2] - 2026-09-22
### Fixed
- Der `--check-config`-Befehl, den `update.sh` in der Zusammenfassung ausgibt,
lief so wie gedruckt nicht (`No module named pdf_ocr_hotfolder`). Das Paket
wird nicht pip-installiert, sondern nach `/opt/pdf-ocr-hotfolder` kopiert und
nur ueber das Arbeitsverzeichnis gefunden — dem Hinweis fehlte das
vorangestellte `cd`. Betraf auch die Beispiele in README.md,
docs/INSTALLATION.md, docs/UPDATE.md und docs/OS-UPGRADE.md.
Gefunden beim Update-Test v0.3.1 -> v0.6.1 auf Debian 12.
## [0.6.1] - 2026-09-22
> **Fuer Bestandsinstallationen wichtig.** Wer 0.6.0 bereits eingespielt hat,
+6 -2
View File
@@ -29,6 +29,10 @@ Weiter: [CHANGELOG.md](CHANGELOG.md) · [AI_AGENT_BRIEFING.md](AI_AGENT_BRIEFING
## Schnellstart
**Voraussetzungen:** Debian 12 oder 13, Python 3.11+, root — und **mindestens
2 GB RAM** (512 MB reichen für 300-dpi-Scans nachweislich nicht, siehe
[Systemanforderungen](docs/INSTALLATION.md#systemanforderungen)).
```bash
git clone gitea@gitea.sonith.de:sonith_ug/pdf-ocr-hotfolder.git
cd pdf-ocr-hotfolder
@@ -93,7 +97,7 @@ deshalb `640 root:<service-gruppe>` und beim Debuggen nicht in Tickets kopieren.
Config prüfen, ohne etwas zu verarbeiten:
```bash
sudo /opt/pdf-ocr-hotfolder/venv/bin/python -m pdf_ocr_hotfolder \
cd /opt/pdf-ocr-hotfolder && sudo ./venv/bin/python -m pdf_ocr_hotfolder \
--check-config --config /etc/pdf-ocr-hotfolder/<instanz>.toml
```
@@ -158,5 +162,5 @@ MIT — © Sonith UG
---
**Version:** 0.6.1
**Version:** 0.6.3
**Repo:** https://gitea.sonith.de/sonith_ug/pdf-ocr-hotfolder
+1 -1
View File
@@ -1 +1 @@
0.6.1
0.6.3
+139 -3
View File
@@ -12,6 +12,7 @@ Verwandte Dokumente: [README](../README.md) · [Update](UPDATE.md) · [Debian-Ma
|-------|-------------|
| Betriebssystem | Debian 12 (bookworm) oder Debian 13 — systemd wird vorausgesetzt |
| Python | 3.11+ (wegen `tomllib` aus der stdlib); kommt aus der Distribution |
| Arbeitsspeicher | **mindestens 2 GB** für den produktiven Betrieb — siehe [Systemanforderungen](#systemanforderungen) |
| Rechte | `root` (`sudo ./install.sh`) |
| Netz | apt-Zugriff für die System-Pakete, PyPI-Zugriff für die venv |
| Repo | muss dauerhaft liegen bleiben — `update.sh` kopiert daraus (s. [UPDATE.md](UPDATE.md)) |
@@ -29,7 +30,7 @@ ca-certificates curl
```
Weitere Tesseract-Sprachpakete installiert der Installer bei Bedarf pro Instanz
nach (siehe [OCR-Sprachen](#3-ocr-sprachen)).
nach (siehe [OCR-Sprachen](#4-ocr-sprachen)).
Die Python-Abhängigkeiten stehen **fest gepinnt** in `requirements.txt`
(ocrmypdf, watchdog, requests, paramiko). Warum das so ist und wie man die Pins
@@ -37,6 +38,92 @@ anhebt: [OS-UPGRADE.md](OS-UPGRADE.md#pins-in-requirementstxt).
---
## Systemanforderungen
CPU und Platte sind unkritisch — **der Arbeitsspeicher ist es nicht.** OCR
rastert jede Seite in voller Auflösung ins RAM; der Spitzenbedarf hängt an der
Seitengröße, nicht an der Dateigröße der PDF.
**Empfehlung: mindestens 2 GB RAM.** Für Mehr-Instanz-Betrieb oder
`max_workers > 2` entsprechend mehr.
### Warum 512 MB nachweislich nicht reichen
Gemessen auf einem LXC-Container mit **512 MB RAM + 512 MB Swap**, Debian 13,
Ghostscript 10.05.1:
| Vorgang | Ergebnis |
|---------|----------|
| eine einzelne **A4-Seite in 300 dpi**, `deskew = true` | cgroup-Limit gerissen, Dienst vom **OOM-Killer** beendet |
| dieselbe Verarbeitung mit einer kleineren Seite (850 × 1100 px) | läuft sauber durch, ca. 19 s |
Beleg aus dem `dmesg` des LXC-Hosts:
```
oom-kill:constraint=CONSTRAINT_MEMCG, oom_memcg=/lxc/201, task=python
total-vm:1168764kB, anon-rss:489676kB
```
Eine Seite, ein Worker — und schon knapp 500 MB anonymer Speicher. 512 MB sind
damit für 300-dpi-Scans keine knappe, sondern eine unzureichende Dimensionierung.
### RAM ↔ `max_workers` × `jobs` × Auflösung
Der Spitzenbedarf multipliziert sich über drei Config-Werte aus
[`[ocr]`](#ocr):
| Key | Default | Wirkung auf den Speicher |
|-----|---------|--------------------------|
| `max_workers` | `2` | **so viele PDFs gleichzeitig** — jede mit eigenem Seitenpuffer. Der direkte Multiplikator |
| `jobs` | `4` | Threads **innerhalb** einer PDF; mehrere Seiten gleichzeitig im Speicher |
| `oversample` | `300` | Auflösung gerasterter Seiten — der Bedarf wächst quadratisch mit der dpi |
Der Default `max_workers = 2` erlaubt also, dass **zwei** solcher Seiten
parallel verarbeitet werden. Wer knapp dimensioniert, zieht zuerst
`max_workers` auf `1` herunter, danach `jobs`. `oversample` unter 300 zu
drücken, spart zwar Speicher, kostet aber Erkennungsqualität — das ist der
letzte Hebel, nicht der erste.
### Wie sich ein OOM-Kill äußert
Von außen sieht ein OOM-Kill wie ein Anwendungsfehler aus — er ist keiner:
- Der Dienst ist **weg** bzw. wurde von systemd neu gestartet
(`Restart=on-failure`); `systemctl show -p NRestarts` steigt.
- Im journal bricht die Verarbeitung **mitten in der Datei** ab, ohne
Python-Traceback und ohne `ERROR`-Zeile aus dem Tool.
- Die betroffene PDF bleibt in `working/` liegen.
### Wie man ihn nachweist
**Im Container:**
```bash
cat /sys/fs/cgroup/memory.events
# oom_kill 1 <- alles über 0 ist ein Treffer
```
**Auf dem LXC-Host** (im Container zeigt `dmesg` diese Zeilen nicht):
```bash
dmesg -T | grep -i oom-kill
```
Diese Prüfung gehört an den **Anfang** der Fehlersuche, wenn Dateien
unerklärlich in `working/` liegen bleiben: ohne sie sucht man den Fehler in
ocrmypdf, Tesseract oder der Config, wo keiner ist.
### Datenverlust ist abgefangen, der OOM bleibt
Seit **v0.6.0** greift der Dienst beim nächsten Start auf, was in `working/`
liegen geblieben ist (siehe [UPDATE.md](UPDATE.md#wiederaufnahme-aus-working)).
Eine vom OOM-Killer unterbrochene Datei geht also nicht verloren. Behoben ist
damit aber nur die Folge: bei unveränderter Dimensionierung läuft dieselbe Datei
nach dem Neustart erneut in denselben OOM — bis `max_workers` sinkt oder das
System mehr RAM bekommt.
---
## Installation
```bash
@@ -471,7 +558,7 @@ Exit 2 heißt immer: Config oder Preflight. Die Ursache steht im journal und
ausführlicher in:
```bash
sudo /opt/pdf-ocr-hotfolder/venv/bin/python -m pdf_ocr_hotfolder \
cd /opt/pdf-ocr-hotfolder && sudo ./venv/bin/python -m pdf_ocr_hotfolder \
--check-config --config /etc/pdf-ocr-hotfolder/<instanz>.toml
```
@@ -480,6 +567,55 @@ sudo /opt/pdf-ocr-hotfolder/venv/bin/python -m pdf_ocr_hotfolder \
Der Interpreter der venv ist weg — fast immer nach einem Distributions-Upgrade.
Siehe [OS-UPGRADE.md](OS-UPGRADE.md).
### Keine Logs: "No journal files were found"
**Symptom:** `journalctl -u pdf-ocr-hotfolder@<instanz>` bleibt leer oder meldet
`No journal files were found.` — auch dann, wenn der Dienst nachweislich läuft
und Dateien verarbeitet.
**Erste Prüfung:**
```bash
systemctl status systemd-journald
```
Ist `systemd-journald.service` selbst `failed` (beobachtet mit
`status=243/CREDENTIALS`), gibt es schlicht kein journal, in das geschrieben
werden könnte.
**Einordnung.** Der Dienst loggt seit v0.4.1 **ausschließlich** nach journald —
es gibt bewusst kein eigenes Logfile und kein Logverzeichnis. Ein kaputtes
journald ist damit ein blinder Fleck: jede Fehlersuche läuft ins Leere, und der
Ausfall sieht aus wie ein stummer Dienst. **Deshalb vor jeder Fehlersuche
zuerst journald prüfen**, nicht erst, wenn nichts anderes mehr passt.
Das ist **kein** generelles LXC-Muster. Von zwei Testcontainern war genau einer
betroffen; auf dem zweiten lief journald einwandfrei. Es handelt sich um einen
Schaden auf dieser einen Maschine, nicht um eine Eigenschaft von Containern.
**Notbehelf, solange journald nicht zu retten ist:** die Instanz einmal im
Vordergrund laufen lassen — dann geht die Ausgabe direkt ins Terminal, am
journal vorbei.
```bash
sudo systemctl stop pdf-ocr-hotfolder@<instanz>
cd /opt/pdf-ocr-hotfolder && sudo -u pdfocr ./venv/bin/python -m pdf_ocr_hotfolder \
--config /etc/pdf-ocr-hotfolder/<instanz>.toml
```
Das `cd` ist zwingend: das Paket wird nicht pip-installiert, sondern nach
`/opt/pdf-ocr-hotfolder` kopiert und nur über das Arbeitsverzeichnis gefunden
(ohne `cd` gibt es `No module named pdf_ocr_hotfolder`, v0.6.2). Beenden mit
`Strg+C`, danach `sudo systemctl start pdf-ocr-hotfolder@<instanz>`. Wer nur den
Bestand abarbeiten und dann aussteigen will, hängt `--once` an (siehe
[Manueller Lauf](#manueller-lauf-one-shot)).
### Dienst bricht mitten in der Verarbeitung weg
Datei bleibt in `working/`, kein Traceback, `NRestarts` steigt: das ist fast
immer der OOM-Killer, kein Anwendungsfehler. Nachweis und Dimensionierung unter
[Systemanforderungen](#wie-sich-ein-oom-kill-äußert).
---
## Manueller Lauf (One-Shot)
@@ -488,7 +624,7 @@ Bestehende PDFs einer Instanz einmalig verarbeiten und beenden — greift auch
Dateien auf, die in `working/` liegen geblieben sind:
```bash
sudo -u pdfocr /opt/pdf-ocr-hotfolder/venv/bin/python -m pdf_ocr_hotfolder \
cd /opt/pdf-ocr-hotfolder && sudo -u pdfocr ./venv/bin/python -m pdf_ocr_hotfolder \
--config /etc/pdf-ocr-hotfolder/kunde-a.toml --once
```
+2 -2
View File
@@ -153,9 +153,9 @@ Instanz, die vorher lief, auch wieder läuft.
**Sind die Configs sauber?**
```bash
cd /opt/pdf-ocr-hotfolder
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"
sudo ./venv/bin/python -m pdf_ocr_hotfolder --check-config --config "$f"
done
```
+1 -1
View File
@@ -284,7 +284,7 @@ Nach dem Code-Update und vor dem Start prüft `update.sh` jede Instanz-Config mi
dem neuen Code:
```bash
/opt/pdf-ocr-hotfolder/venv/bin/python -m pdf_ocr_hotfolder \
cd /opt/pdf-ocr-hotfolder && ./venv/bin/python -m pdf_ocr_hotfolder \
--check-config --config /etc/pdf-ocr-hotfolder/<instanz>.toml
```
+1 -1
View File
@@ -1,3 +1,3 @@
"""PDF OCR Hotfolder — Scanner-PDFs automatisch durchsuchbar machen."""
__version__ = "0.6.1"
__version__ = "0.6.3"
+3 -1
View File
@@ -1243,7 +1243,9 @@ if [ "${#CFG_WARN[@]}" -gt 0 ]; then
log_warn "Config-Warnungen (Exit 1) bei: ${CFG_WARN[*]}"
log_warn " Kein Abbruchgrund, aber bitte nachsehen:"
for name in "${CFG_WARN[@]}"; do
log_warn " $INSTALL_DIR/venv/bin/python -m pdf_ocr_hotfolder --check-config --config $CONFIG_DIR/$name.toml"
# Das Paket ist nicht pip-installiert, sondern liegt in $INSTALL_DIR —
# ohne das cd findet Python das Modul nicht.
log_warn " cd $INSTALL_DIR && ./venv/bin/python -m pdf_ocr_hotfolder --check-config --config $CONFIG_DIR/$name.toml"
done
fi
if [ "$APT_WARN" -eq 1 ]; then