Zum Inhalt

Worker & Benachrichtigungen

Der Worker-Prozess

scripts/worker.ts startet eine pg-boss-Instanz und registriert alle Queues und Scheduler. Eine Instanz genügt. Lokal: pnpm worker. Im Container: node --import tsx scripts/worker.ts, direkt mit node gestartet, damit SIGTERM den geordneten Shutdown auslöst.

Der Worker braucht DATABASE_URL und denselben SETTINGS_ENCRYPTION_KEY wie die Web-App, außerdem APP_URL, weil er beim Versand Links auf die Statusseite baut. SESSION_SECRET braucht er nicht.

Queue / Job Aufgabe Auslöser
email-send Versand von E-Mails (über lib/email/) Ereignis
sms-send SMS-Versand über Twilio Ereignis
webhook-dispatch Zustellung von Webhooks, signiert per HMAC Ereignis
push-send Versand von Web-Push-Nachrichten Ereignis
maintenance-transitions Sendet maintenance_started einmalig für laufende Fenster ohne Startmarkierung und setzt abgelaufene Wartungen still auf completed. Beide Sweeps laufen unabhängig voneinander. Jede Minute
uptime-check-sweep Führt HTTP-Checks für fällige, nicht pausierte Komponenten mit aktivierten Checks aus Jede Minute
notification-event-reaper Setzt E-Mail-Events, die länger als 30 Minuten in pending/processing hängen, auf failed Alle 10 Minuten
failed-notification-alert Loggt eine Warnung „notification events failed in the last window“ mit Anzahl und bis zu 50 Event-IDs, wenn in den letzten 10 Minuten E-Mail-Events fehlgeschlagen sind. Grundlage für logbasiertes Alerting, es wird nichts versendet. Alle 10 Minuten
uptime-check-retention Löscht Uptime-Check-Ergebnisse, die älter als 30 Tage sind Täglich um 03:00
verify-token-cleanup Leert den Bestätigungs-Token bestätigter Abonnenten, deren Bestätigung älter als 30 Tage ist Täglich um 03:00

Beim Start führt der Worker außerdem ensureNotificationTemplateRows() aus. Fehlt für einen Event-Typ die Template-Zeile, wird sie mit allen Kanälen aktiv angelegt.

Dispatch-Pipeline

Jede Benachrichtigung durchläuft denselben Weg:

  1. Eine Fachaktion ruft dispatchNotification (lib/notifications/notify.ts) mit Event-Typ und betroffenen Entitäten auf.
  2. Stummschaltung wird geprüft: Sind alle betroffenen Komponenten stummgeschaltet, wird nichts gesendet (skipped_disabled). Kanal-Schalter je Komponente werden separat geprüft.
  3. Template-Gates werden je Kanal geprüft (mail, sms, webhook, push). Jeder Kanal hat ein eigenes Aktivierungs-Flag in notification_templates. Fail-closed: Ohne Zeile wird nicht gesendet.
  4. Mail-only-Typen (MAIL_ONLY_EVENT_TYPES in lib/notifications/mail-only.ts, derzeit double_optin) gehen nur per E-Mail. Webhook, SMS und Push werden für sie übersprungen, unabhängig von den Flags.
  5. Je Kanal entstehen Zustellzeilen:
  6. E-Mail: eine Zeile in notification_events und ein Job, sofern ein Provider eingerichtet ist und es Empfänger gibt.
  7. Webhook, SMS, Push: je Endpunkt, Empfänger bzw. Abo eine Zeile in webhook_deliveries, sms_deliveries bzw. push_deliveries und je Zeile ein Job.
  8. Der Processor sendet. Jede Zustellung hat bis zu 3 Versuche mit Wartezeiten von 2 und danach 4 Sekunden. Das Ergebnis landet in der Zustelltabelle des Kanals.

Die Kanäle sind unabhängig. Ein deaktivierter E-Mail-Kanal blockiert SMS und Webhooks nicht.

Kanäle

Kanal Empfänger Transport Hinweise
E-Mail Benutzerkonten und bestätigte Abonnenten (je nach Abo-Modus), E-Mail-Adresse je Komponente SMTP (nodemailer) oder Resend Templates je Event-Typ sind im Admin editierbar. Abonnenten-Mails nutzen Double Opt-in. Versand in Empfänger-Blöcken per BCC.
Webhook Konfigurierte Endpunkte, optional gefiltert nach Event-Typ HTTP POST, 10 Sekunden Timeout je Versuch Header X-SLAtus-Signature: sha256=<hex>, X-SLAtus-Event und X-SLAtus-Delivery. Zieltypen generic, slack, teams, discord formatieren den Body für das Zielsystem. Secrets sind rotierbar.
SMS Vom Admin verwaltete Telefonnummern Twilio-REST-API Text aus einem festen Builder, auf 300 Zeichen gekürzt. Keine Selbstanmeldung.
Web-Push Browser-Abos, die Besucher selbst anlegen web-push mit VAPID-Schlüsseln Abos, die mit HTTP 404 oder 410 antworten, werden automatisch gelöscht.

Bei Webhooks wird die HMAC-Signatur über den formatierten Body berechnet, der tatsächlich gesendet wird.

Event-Typen

Die Event-Typen sind in NOTIFICATION_EVENT_TYPES (lib/db/schema.ts) definiert, u. a.: double_optin, outage_started, service_operational, service_outage_change, incident_created, incident_updated, incident_resolved, incident_reviewed, incident_closed, maintenance_scheduled, maintenance_started, maintenance_completed und sla_report_started.

double_optin ist mail-only. Serverseitig lehnen fanOutEventTypesSchema (lib/validations/event-types.ts, Event-Filter von SMS, Webhook und Push) und setNotificationTemplateChannelEnabledAction (Kanal-Flags) diesen Typ ab.

Wiederholungen und Fehler

  • Wiederholungen finden nur im Processor statt, also genau eine Retry-Ebene. pg-boss nutzt retryLimit: 1 nur als Absicherung gegen Abstürze.
  • Kein Processor wirft. Eine unerwartete Exception setzt die Zustellung auf failed mit lastError „unexpected error: …“. Beim E-Mail-Processor bleibt sent_chunks dabei unverändert.
  • E-Mails werden in Empfänger-Blöcken versendet. notification_events.sent_chunks hält fest, wie viele Blöcke schon zugestellt sind. Jeder Versuch, der Crash-Retry von pg-boss und das manuelle Resend setzen dort fort, niemand bekommt eine Mail doppelt.
  • E-Mail-Events, die alle Versuche verbraucht haben, können unter /admin/notification-events erneut gesendet werden. Dabei wird die Zeile auf pending zurückgesetzt und erneut eingereiht. Bei teilweise zugestellten Events heißt der Button Resend remaining.
  • failed-notification-alert meldet fehlgeschlagene E-Mail-Events alle 10 Minuten im Log (Issue #126).