Files
Webklar-Kundenbereich/server/services/zeiten/jobs.js
T
ClaudeandClaude Opus 5.5 a198c472bd Öffnungszeiten: Feiertags-Erinnerung und Jobs
erinnereFeiertage(now): stündlich, nur bei Schalter pilot/on (pilot: nur
freigegebene Kunden) und nur 08:00 bis 20:00 Berliner Zeit; je Funktion in
setup/active zuerst der Merker sha1(featureId|datum) je Tag (409 = schon
erinnert), danach eine Mail K25 mit allen neuen Tagen ohne BCC ans Team;
Merker älter als 30 Tage werden gelöscht. zeitenAboJob (täglich) und
zeitenErinnerungsJob (stündlich) mit eigener Überlappsperre, ohne Wurf;
in server/index.js nach 240 s bzw. 300 s gestartet, mit unref.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 03:40:07 +00:00

62 lines
3.2 KiB
JavaScript

import { gleicheZeitenAboAb } from './aboAbgleich.js'
import { erinnereFeiertage } from './erinnerung.js'
/**
* Hintergrund-Jobs von Öffnungszeiten live (Spezifikation 2026-10-04-oeffnungszeiten-live-design.md, Abschnitte 5 und 7).
* server/index.js ruft sie mit new Date() auf; `now` ist hier immer ein Parameter.
*
* zeitenAboJob täglich (240 s nach dem Start beginnend) Abo-Abgleich (aboAbgleich.js): Abo-Ende erkennen, nach 30 Tagen
* abschalten, bei Rückkehr wieder einschalten, nach weiteren 30 Tagen
* löschen. Eigener Tagesjob, nicht an den Schalter ZEITEN_ENABLED
* gekoppelt (wie beim Terminplaner): ein beendetes Abo muss auch bei
* Schalter off zum Abschalten und zur Löschung führen. Ohne Zeiten-
* Dokumente kostet er eine Abfrage.
* zeitenErinnerungsJob stündlich (300 s nach dem Start beginnend) Feiertags-Erinnerung (erinnerung.js): nur bei Schalter pilot/on,
* nur 08:00 bis 20:00 Berliner Zeit, Merker älter als 30 Tage löschen
*
* Gemeinsame Regeln:
* - Keine überlappenden Läufe, je Job: läuft ein Job noch, kehrt der nächste Takt sofort mit { uebersprungen: true } zurück (einmal
* im Log je Überlappung). Die Sperre ist ein Merker im Speicher des Prozesses (ein Server, ein Prozess); die Jobs sperren einander nicht.
* - Ein Job wirft nie: ein unerwarteter Fehler (etwa ein ungültiges `now`) steht im Log, das Ergebnis ist { fehler: 1 }. Die Bausteine
* melden einzelne Fehler selbst im Ergebnis (`fehler`).
* - Das Log nennt weder Namen noch Adressen von Kunden.
*/
const laufend = new Set()
const ueberlappGemeldet = new Set()
const fehlerText = (err) => `${err?.name ?? 'Fehler'} ${String(err?.message ?? '').slice(0, 200)}`
/** Führt arbeit() aus, sofern dieser Job nicht schon läuft; fängt jeden Fehler. */
async function fuehreAus(job, arbeit) {
if (laufend.has(job)) {
if (!ueberlappGemeldet.has(job)) {
ueberlappGemeldet.add(job)
console.warn(`[zeiten-jobs] ${job}: der vorige Lauf ist noch nicht fertig, dieser Takt wird übersprungen`)
}
return { uebersprungen: true }
}
laufend.add(job)
try {
return await arbeit()
} catch (err) {
console.error(`[zeiten-jobs] ${job} fehlgeschlagen: ${fehlerText(err)}`)
return { fehler: 1 }
} finally {
laufend.delete(job)
ueberlappGemeldet.delete(job)
}
}
/** Täglicher Abo-Abgleich. => Ergebnis von gleicheZeitenAboAb | { uebersprungen: true } | { fehler: 1 } */
export const zeitenAboJob = (now) => fuehreAus('zeitenAboJob', () => gleicheZeitenAboAb(now))
/** Stündliche Feiertags-Erinnerung. => Ergebnis von erinnereFeiertage | { uebersprungen: true } | { fehler: 1 } */
export const zeitenErinnerungsJob = (now) => fuehreAus('zeitenErinnerungsJob', () => erinnereFeiertage(now))
/** Nur für Tests: alle Sperren freigeben. */
export function resetZeitenJobsForTests() {
laufend.clear()
ueberlappGemeldet.clear()
}