feat: Sync-Intervall über SYNC_INTERVAL konfigurierbar (Standard: 15m)
This commit is contained in:
+12
-5
@@ -9,10 +9,17 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// maxSyncAge ist die maximale Dauer seit dem letzten Sync-Lauf, bevor der
|
||||
// Healthcheck den Daemon als unhealthy meldet. Da der Sync alle 15 Minuten
|
||||
// läuft, erlauben wir 20 Minuten Toleranz.
|
||||
const maxSyncAge = 20 * time.Minute
|
||||
// maxSyncAge berechnet die maximale Dauer seit dem letzten Sync-Lauf, bevor
|
||||
// der Healthcheck den Daemon als unhealthy meldet. Die Toleranz beträgt
|
||||
// 5 Minuten über dem konfigurierten Sync-Intervall.
|
||||
func maxSyncAge() time.Duration {
|
||||
syncInterval, err := parseSyncInterval()
|
||||
if err != nil {
|
||||
// Fallback: 20 Minuten (15m Standard-Intervall + 5m Toleranz).
|
||||
return 20 * time.Minute
|
||||
}
|
||||
return syncInterval + 5*time.Minute
|
||||
}
|
||||
|
||||
// healthFile ist der Dateiname der Healthcheck-Statusdatei, die neben dem
|
||||
// State-File abgelegt wird.
|
||||
@@ -73,7 +80,7 @@ func runHealthcheck() error {
|
||||
if s.LastError != "" {
|
||||
return fmt.Errorf("last sync failed: %s", s.LastError)
|
||||
}
|
||||
if time.Since(s.LastSync) > maxSyncAge {
|
||||
if time.Since(s.LastSync) > maxSyncAge() {
|
||||
return fmt.Errorf("last sync too old: %s ago", time.Since(s.LastSync).Round(time.Second))
|
||||
}
|
||||
return nil
|
||||
|
||||
+26
-1
@@ -37,6 +37,7 @@ type Daemon struct {
|
||||
oldCalendarName string
|
||||
notificationEnabled bool
|
||||
notificationTrigger string
|
||||
syncInterval time.Duration
|
||||
health *healthState
|
||||
}
|
||||
|
||||
@@ -85,6 +86,12 @@ func run() error {
|
||||
calendarName = "Birthdays"
|
||||
}
|
||||
notificationEnabled := strings.EqualFold(os.Getenv("NOTIFICATION_ENABLED"), "true")
|
||||
syncInterval, err := parseSyncInterval()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
slog.Info("sync interval configured", "interval", syncInterval)
|
||||
|
||||
notificationTrigger := "PT8H"
|
||||
if notificationEnabled {
|
||||
notificationTime := os.Getenv("NOTIFICATION_TIME")
|
||||
@@ -107,6 +114,7 @@ func run() error {
|
||||
calendarName: calendarName,
|
||||
notificationEnabled: notificationEnabled,
|
||||
notificationTrigger: notificationTrigger,
|
||||
syncInterval: syncInterval,
|
||||
}
|
||||
if len(d.stateFilepath) == 0 {
|
||||
d.stateFilepath = "state.json"
|
||||
@@ -131,7 +139,7 @@ func (d *Daemon) daemonLoop() {
|
||||
if err != nil {
|
||||
slog.Error("error while syncing birthdays", "err", err)
|
||||
}
|
||||
time.Sleep(time.Minute * 15)
|
||||
time.Sleep(d.syncInterval)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,6 +274,23 @@ func runCleanup() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseSyncInterval liest SYNC_INTERVAL aus der Umgebung und gibt die
|
||||
// geparste Dauer zurück. Standard: 15m.
|
||||
func parseSyncInterval() (time.Duration, error) {
|
||||
raw := os.Getenv("SYNC_INTERVAL")
|
||||
if raw == "" {
|
||||
return 15 * time.Minute, nil
|
||||
}
|
||||
d, err := time.ParseDuration(raw)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid SYNC_INTERVAL %q: %w", raw, err)
|
||||
}
|
||||
if d < 1*time.Minute {
|
||||
return 0, fmt.Errorf("SYNC_INTERVAL must be at least 1m, got %s", d)
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// buildTransport erstellt einen http.Transport.
|
||||
// Wenn MAILCOW_RESOLVE_HOST gesetzt ist (z. B. "nginx-mailcow"), wird der
|
||||
// tatsächliche TCP-Connect auf diesen Host umgeleitet, während TLS-SNI und
|
||||
|
||||
Reference in New Issue
Block a user