Terminplaner: Hintergrund-Jobs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
efe17551c2
commit
485ff3bc15
6 files changed
+1428
-3
No files matched your search
@@ -3,7 +3,7 @@ import { Query, createDocument, deleteDocument, getDocument, listAllDocuments, u
|
||||
import { withLocks } from '../keyedLock.js'
|
||||
import { sendGuestMail } from '../mailer.js'
|
||||
import { renderMail } from '../mailTemplates.js'
|
||||
import { pruefeNow, pruefeText } from './util.js'
|
||||
import { pruefeNow, pruefeText, zeitMs } from './util.js'
|
||||
|
||||
/**
|
||||
* Mail-Warteschlange des Terminplaners (termineOutbox; Spezifikation 2026-10-02-terminplaner-design.md, Abschnitt 6).
|
||||
@@ -39,6 +39,8 @@ const WIEDERHOLUNG_MS = [1 * MIN_MS, 5 * MIN_MS, 30 * MIN_MS]
|
||||
const ANMELDE_PAUSE_MS = 15 * MIN_MS
|
||||
const GESENDET_BEHALTEN_MS = 7 * TAG_MS
|
||||
const FEHLER_BEHALTEN_MS = 48 * STUNDE_MS
|
||||
/** Laenger als das in `wartet` (ab createdAt) ist ein Eintrag festgefahren (beendeFestgefahrene). */
|
||||
const WARTEN_MAX_MS = 48 * STUNDE_MS
|
||||
const ICS_METHODEN = ['REQUEST', 'CANCEL', 'PUBLISH']
|
||||
/** Buchungs-IDs je Abfrage in zustellFehler (haelt die Adresse kurz). */
|
||||
const ID_BLOCK = 50
|
||||
@@ -314,6 +316,41 @@ export async function raeumeAuf(now) {
|
||||
return geloescht
|
||||
}
|
||||
|
||||
/**
|
||||
* Taeglicher Job, vor raeumeAuf: Eintraege, die laenger als 48 Stunden (ab createdAt) in `wartet` stehen, werden zu
|
||||
* `fehler` (das Portal zeigt dann den Zustellhinweis) und bekommen als Loeschtermin jetzt + 48 Stunden, damit raeumeAuf
|
||||
* sie erst dann loescht und nicht noch im selben Lauf. Je Eintrag unter der Sendesperre `termine-mail:<id>` nach neuem
|
||||
* Lesen: ein Eintrag, der inzwischen gesendet wurde (oder dessen Versand gerade laeuft), bleibt, wie er ist.
|
||||
* @param {Date} now
|
||||
* @returns {Promise<number>} Anzahl beendeter Eintraege
|
||||
*/
|
||||
export async function beendeFestgefahrene(now) {
|
||||
const nowMs = pruefeNow(now, 'beendeFestgefahrene')
|
||||
const grenze = nowMs - WARTEN_MAX_MS
|
||||
const alt = (await listAllDocuments(col(), [Query.equal('status', 'wartet')])).filter((eintrag) => zeitMs(eintrag.createdAt) < grenze)
|
||||
let beendet = 0
|
||||
for (const eintrag of alt) {
|
||||
const geaendert = await withLocks([`termine-mail:${eintrag.$id}`], async () => {
|
||||
let frisch
|
||||
try {
|
||||
frisch = await getDocument(col(), eintrag.$id)
|
||||
} catch (err) {
|
||||
if (err.status === 404) return false
|
||||
throw err
|
||||
}
|
||||
if (frisch.status !== 'wartet' || !(zeitMs(frisch.createdAt) < grenze) || unverbucht.has(frisch.$id)) return false
|
||||
await updateDocument(col(), frisch.$id, {
|
||||
status: 'fehler',
|
||||
naechsterVersuch: iso(nowMs + FEHLER_BEHALTEN_MS),
|
||||
fehler: 'Nicht zugestellt: länger als 48 Stunden in der Warteschlange.',
|
||||
})
|
||||
return true
|
||||
})
|
||||
if (geaendert) beendet += 1
|
||||
}
|
||||
return beendet
|
||||
}
|
||||
|
||||
/** Ende der letzten Anmeldepause (Date) oder null, wenn es noch keine gab. Eine Pause gilt, solange das Ende nach `now` liegt. */
|
||||
export function pausiertBis() {
|
||||
return pauseBisMs ? new Date(pauseBisMs) : null
|
||||
|
||||
Reference in new issue
Block a user