Neues config.yml-Feld batch_mode (index/ocr, Default false = unverändertes Verhalten). Bei batch_mode:true verarbeiten neue Cron-Jobs (index-pending, ocr-reprocess) die Backlogs in größeren Abständen statt sofort bei jedem Mail-Import, um Schreiblast auf der Festplatte zu glätten. Zeiten in /etc/cron.d/archivmail frei anpassbar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.1 KiB
7.1 KiB
PROJ-58: Indexierung + OCR als Cron-Batch-Jobs (statt Dauerbetrieb)
Status: Deployed
Created: 2026-06-24 Last Updated: 2026-06-24
Dependencies
- PROJ-30 (Manticore-Indexierung)
- PROJ-35 (OCR & Anhang-Volltext-Indexierung)
- PROJ-56 (Last-Entzerrung für Hintergrundjobs — verwandtes Cron-Muster)
Hintergrund (Nutzerwunsch)
Aktuell laufen Indexierung (internal/index/tenant_worker.go) und OCR (internal/ocr/worker.go) sofort und nebenläufig bei jedem Mail-Import als Dauerbetrieb-Goroutinen. Das erzeugt viele kleine Schreibzugriffe auf die Festplatte (Manticore-Writes, OCR-Tesseract-Output, DB-Updates) statt geblockter Batches. Nutzerwunsch: Beide Prozesse sollen optional in größeren, per cron.d konfigurierbaren Zeitabständen laufen, damit die Zeiten später selbst angepasst werden können (analog zum bestehenden Purge-Cron, PROJ-56c).
Bestehende Bausteine (bereits vorhanden, lt. Code-Analyse)
indexed_at TIMESTAMPTZ(storage.go) markiert bereits indexierte Mails — Query aufindexed_at IS NULLliefert die Pending-Liste ohne neue Spalte.ocr_status(pending/done/failed/skipped/disabled) ist bereits vollständig vorhanden.cmd_ocr_reprocess.goist bereits "lade Batch → verarbeite → beenden" und damit direkt cron-fähig.- Es fehlt ein äquivalenter Batch-Befehl für die Indexierung (aktuell nur
cmd_reindex.go, das immer alle Mails neu indexiert statt nur die ungeindexten — ungeeignet für einen häufigen Cron-Lauf).
Entscheidung (Nutzer, 2026-06-24)
- Modus per Config umschaltbar (
index.batch_mode,ocr.batch_mode), Defaultfalse= aktuelles Verhalten unverändert (non-breaking, analog PROJ-56). - Bei
batch_mode: truewird der jeweilige Dauerbetrieb-Worker im Daemon nicht gestartet; neue Mails bleiben bis zum nächsten Cron-Lauf mitindexed_at IS NULL/ocr_status='pending'in der DB stehen (kein Datenverlust, nur verzögerte Sichtbarkeit in Suche/OCR). - Zeiten stehen in
/etc/cron.d/archivmail, frei editierbar, mit demselben Kommentarstil wie der bestehende OCR-Pausen- und Purge-Cron.
Acceptance Criteria
- Neuer CLI-Befehl
archivmail index-pending --config ... --limit Nlädt Mails mitindexed_at IS NULL(Query-Pattern analogcmd_ocr_reprocess.go), indexiert sie über denTenantIndexWorker, wartet auf vollständiges Drain, beendet sich danach. config.yml: neue Felderindex.batch_mode(bool, default false) undocr.batch_mode(bool, default false).- Bei
batch_mode: truewird der jeweilige Worker beim Daemon-Start nicht gestartet und der Upload-Pfad submitted nicht mehr in den In-Memory-Channel (kein sinnloses Queue-Volllaufen/Log-Spam). - Bei
batch_mode: false(Default) bleibt das bisherige Verhalten 1:1 erhalten — keine Regression für bestehende Installationen. deploy/cron.d/archivmailbekommt zwei neue, kommentierte Cron-Zeilen fürindex-pendingundocr-reprocess --status pending, mit Beispiel-Intervall (z.B. alle 15 Minuten), klar als "Zeiten hier anpassen" markiert — analog zum bestehenden OCR-Pausenfenster-Kommentarstil.- Boot-Resume-Goroutinen (OCR-Backfill in main.go, Index-Backfill
runBackfill) laufen nur, wenn der jeweiligebatch_modenicht aktiv ist (sonst übernimmt der Cron-Job diese Aufgabe). - Dokumentation im Cron-File erklärt, dass bei
batch_mode: trueneue Mails erst nach dem nächsten Cron-Lauf durchsuchbar/OCR-bearbeitet sind.
Tech Design
Übersprungen (klar umrissene, additive Konfigurationsoption mit bestehenden Bausteinen — kein architektonischer Schnitt, analog PROJ-56).
Implementation Notes (2026-06-24)
Geänderte/neue Dateien
config/config.go: neues FeldBatchMode bool(yaml:"batch_mode", default false) inIndexConfigundOCRConfig. Additiv/non-breaking, kein Pointer nötig dafalseder gewünschte Default ist.internal/storage/storage.go: neue FunktionGetUnindexedMails(ctx, limit)+ TypUnindexedMail{ID, TenantID}— QueryWHERE indexed_at IS NULL ORDER BY received_at DESC(analog zuGetMailsByOCRStatus).cmd/archivmail/cmd_index_pending.go(neu): CLI-Befehlindex-pending(Flags--config,--limit), Vorbildcmd_ocr_reprocess.go. Lädt ungeindexte Mails, parst sie, bautindex.MailDocument, queued sie auf einen frisch erstelltenTenantIndexWorker(Queue = batch+16, kein Drop), setztindexed_at, wartet viaworker.Stop()auf vollständiges Drain, beendet sich.cmd/archivmail/main.go: Befehl im Dispatcher registriert. Daemon-Start gated: beicfg.Index.BatchModekeintenantWorker.Start()und keinrunBackfill; beicfg.OCR.BatchModekeinocrWorker.Start(), keine OCR-Boot-Resume-Goroutine, keine IMAP/POP3-SetOCRSubmit-Hooks.submitToWorker()um zwei Flags (indexBatchMode,ocrBatchMode) erweitert → überspringt die jeweiligen In-Memory-Submits (kein Queue-Volllaufen / Log-Spam). Mails behalten dabeiindexed_at IS NULLbzw.ocr_status='pending'und werden vom Cron-Job nachgezogen.deploy/cron.d/archivmail: zwei neue, kommentierte Zeilen (index-pending*/15,ocr-reprocess --status pending5,20,35,50), klar als nur-bei-batch_mode:true-relevant und frei editierbar markiert.config/config.docker.yml.example: auskommentierte Beispiele fürindex.batch_modeundocr.batch_mode.
Design-Entscheidungen / Abweichungen
BatchModeist ein einfacherbool(kein Pointer wie bei PROJ-56JitterSeconds), da hierfalse= Default = gewünschtes Alt-Verhalten; eine Unterscheidung unset/explizit-false ist nicht nötig.- IMAP/POP3-Importer indexieren synchron direkt über
idxMgr(nicht über denTenantIndexWorker) — dieser Pfad bleibt unverändert;index.batch_modebetrifft bewusst nur den Worker-/SMTP-Upload-Pfad (Schreiblast-Glättung des Async-Workers). OCR-Hooks der Importer werden hingegen beiocr.batch_modedeaktiviert, da OCR ausschließlich über den Worker läuft. - Lokal kein
go buildmöglich (kein Toolchain) — nur statische Konsistenzprüfung; Build-Verifikation auf 192.168.1.131/132.
QA Test Results (192.168.1.132, 2026-06-24)
- Build:
CGO_ENABLED=0 go build -buildvcs=false -o archivmail ./cmd/archivmail/→ Exit 0. go vet ./...: nur vorbestehende, PROJ-58-unabhängige Befunde (xapian_wrapper.cpp/cgo, storage.go self-assignment, storage_test.go-Signatur). Keine neuen Befunde durch PROJ-58.- Default-Verhalten (
batch_modeunset/false): Live-Service unverändert weitergelaufen, kontinuierliche Indexierung/OCR + Boot-Backfill bestätigt aktiv,/api/healthok. batch_mode: true(isolierte Test-Config): Daemon startet, loggt "batch mode enabled — continuous worker not started" für beide Worker, kein Backfill/Boot-Resume, keine kontinuierliche Verarbeitung — wie spezifiziert.index-pending --limit 5gegen Test-DB: 5 ungeindexte Mails geladen, Worker drained, Exit 0.- Minor-Finding behoben:
index-pendingfehlte inprintHelp()(cmd_import.go) — ergänzt. - Keine Critical/High-Findings. Server 192.168.1.131 nicht angefasst während der QA.
Out of Scope
- Kein Wechsel der bestehenden Mechanismen für Installationen, die
batch_modenicht setzen. - Kein UI/Admin-Schalter im Frontend — Konfiguration ausschließlich über
config.yml+cron.d.