feat(PROJ-56): Last-Entzerrung für OCR und IMAP-Sync

OCR-Worker pausieren optional in konfigurierbarem Zeitfenster
(paused_hours), Jobs bleiben pending statt verworfen zu werden.
IMAP-Scheduler verteilt Sync-Starts via deterministischem
Pro-Account-Jitter, um Lastspitzen bei vielen Postfächern mit
gleichem Intervall zu vermeiden. Beides per Config opt-out,
Default-Verhalten unverändert. Build + Smoke-Test auf 132 verifiziert.
This commit is contained in:
sysops
2026-06-22 14:21:09 +02:00
parent a55faf74b1
commit 4dbf27cc1d
7 changed files with 261 additions and 12 deletions
+16
View File
@@ -54,6 +54,22 @@ imap_server:
enabled: false
bind: "0.0.0.0:1143"
# PROJ-56: OCR-Last-Entzerrung (optional).
# paused_hours definiert ein lokales Zeitfenster [start, end), in dem der
# OCR-Worker NICHT verarbeitet (Aufträge bleiben als pending erhalten).
# Wrap-around über Mitternacht wird unterstützt, z.B. [22, 6] = Pause 22:0006:00.
# Ohne Sektion / ohne paused_hours: altes Verhalten (immer aktiv).
# ocr:
# paused_hours: [8, 18] # OCR pausiert während der Geschäftszeiten
# PROJ-56: IMAP-Sync-Jitter (optional).
# jitter_seconds verteilt den tatsächlichen Sync-Start jedes Accounts
# deterministisch (abgeleitet aus Account-ID) über dieses Fenster, damit nicht
# alle Postfächer auf derselben Minutengrenze pollen.
# Weglassen der Sektion = Default 240s (4 Min). jitter_seconds: 0 = deaktiviert.
# imap_scheduler:
# jitter_seconds: 240
audit:
log_path: /var/archivmail/audit.log
retention_days: 365
+41
View File
@@ -39,6 +39,47 @@ type Config struct {
Logging LoggingConfig `yaml:"logging"`
IMAPServer IMAPServerConfig `yaml:"imap_server"`
Metrics MetricsConfig `yaml:"metrics"`
// PROJ-56: load-spreading for background jobs.
OCR OCRConfig `yaml:"ocr"`
IMAPScheduler IMAPSchedulerConfig `yaml:"imap_scheduler"`
}
// OCRConfig holds settings for the background OCR worker (PROJ-56).
type OCRConfig struct {
// PausedHours optionally defines a local-time window [start, end) during
// which the OCR worker pauses processing (e.g. [8, 18] = paused 08:0018:00).
// Wrap-around windows are supported, e.g. [22, 6] = paused 22:0006:00.
// nil / unset = never pause (legacy behaviour: process immediately).
PausedHours *[2]int `yaml:"paused_hours,omitempty"`
}
// IMAPSchedulerConfig holds settings for the automatic IMAP sync scheduler (PROJ-56).
type IMAPSchedulerConfig struct {
// JitterSeconds spreads the per-account sync start over a deterministic
// offset derived from the account ID, so N accounts on the same interval
// don't all poll on the same minute boundary.
// A pointer so the unset case (use default) is distinguishable from an
// explicit 0 (disable jitter).
// nil -> DefaultIMAPJitterSeconds (240s window)
// 0 -> jitter disabled (legacy behaviour)
// >0 -> jitter window in seconds
JitterSeconds *int `yaml:"jitter_seconds,omitempty"`
}
// DefaultIMAPJitterSeconds is the jitter window applied when imap_scheduler
// is omitted entirely from the config (4 minutes).
const DefaultIMAPJitterSeconds = 240
// ResolvedJitterSeconds returns the effective jitter window. nil falls back to
// the default; an explicit 0 (or negative) means jitter is disabled.
func (c IMAPSchedulerConfig) ResolvedJitterSeconds() int {
if c.JitterSeconds == nil {
return DefaultIMAPJitterSeconds
}
if *c.JitterSeconds < 0 {
return 0
}
return *c.JitterSeconds
}
// IMAPServerConfig holds settings for the embedded read-only IMAP archive server.