feat(PROJ-56): OCR-Pausenfenster per SIGHUP-Reload statt Restart

paused_hours konnte bisher nur über einen vollen Prozess-Restart geändert
werden, was SMTP/IMAP/API unnötig unterbricht. Worker.pausedHours ist jetzt
ein atomic.Pointer mit SetPausedHours(); SIGHUP liest config.yml neu und
aktualisiert nur die OCR-Pausenzeit im laufenden Prozess. Neue
deploy/cron.d/archivmail-ocr-pause(.sh) lässt Admins die Pausenzeiten direkt
in der Cron-Datei pflegen und löst per systemctl reload statt restart aus.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-06-24 14:46:13 +02:00
co-authored by Claude Sonnet 4.6
parent be48a99af9
commit dba9939880
5 changed files with 119 additions and 12 deletions
+30
View File
@@ -474,6 +474,17 @@ func main() {
}
}()
// PROJ-56b: SIGHUP reloads only the OCR pause window from config.yml, so
// admins/cron can change paused_hours without a full service restart
// (which would otherwise drop SMTP/IMAP connections unnecessarily).
reload := make(chan os.Signal, 1)
signal.Notify(reload, syscall.SIGHUP)
go func() {
for range reload {
reloadOCRPauseWindow(*configPath, ocrWorker, logger)
}
}()
// Graceful shutdown
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
@@ -485,6 +496,25 @@ func main() {
httpServer.Shutdown(ctx)
}
// reloadOCRPauseWindow re-reads config.yml and applies any change to
// ocr.paused_hours to the already-running OCR worker, without restarting
// the process. Other config sections are intentionally ignored — a full
// reload of e.g. DB DSN or listen ports would require a restart anyway.
func reloadOCRPauseWindow(configPath string, ocrWorker *ocr.Worker, logger *slog.Logger) {
cfg, err := config.Load(configPath)
if err != nil {
logger.Warn("sighup reload: config read failed, keeping current pause window", "err", err)
return
}
ocrWorker.SetPausedHours(cfg.OCR.PausedHours)
if cfg.OCR.PausedHours != nil {
logger.Info("sighup reload: ocr pause window updated",
"from_hour", cfg.OCR.PausedHours[0], "to_hour", cfg.OCR.PausedHours[1])
} else {
logger.Info("sighup reload: ocr pause window cleared")
}
}
// submitToWorker parses a raw email and submits it to the async index worker.
// tenantID may be nil for global context.
// If ocrWorker is non-nil and the mail has attachments, an OCR job is also