Reliability Engineering
Stabilisierung nächtlicher Leistungsjobs
Ein nächtlicher Terminverarbeitungsjob wirkte in Produktion gesund, ließ aber stillschweigend wiederherstellbare verrechenbare Leistungen liegen. Ich baute den Lauf rund um begrenzte Batches, Caching, Fehlerisolation und kategorisiertes Reporting um.
Wichtige Kennzahlen
- Wiederhergestellte Leistungen
- rund 5.300
- Fehlergrenze
- pro Termin
- Laufstruktur
- fensterbasiert und gechunkt
Problem
Ein nächtlicher Terminverarbeitungsjob war dafür zuständig, aktuelle klinische Termine zu finden, zu prüfen, welchen Terminen noch verrechenbare medizinische Leistungen fehlten, diese Termine den passenden Leistungsblöcken zuzuordnen und die generierten Leistungen zurück in den Verrechnungsworkflow zu schreiben.
Auf dem Papier wirkte der Job einfach. In Produktion ließ er aber stillschweigend wiederherstellbare Arbeit liegen. Manche Termine wurden übersprungen, weil der Lauf zu viele Daten auf einmal verarbeitete. Andere scheiterten, weil ein ungültiger Leistungsblock oder eine fehlende Konfiguration den Pfad für eigentlich valide Termine unterbrechen konnte.
Ich untersuchte die fehlenden Leistungen end to end und refactorisierte den nächtlichen Job anschließend rund um Batching, Caching, Fehlerisolation und operative Sichtbarkeit. Der stabilisierte Job half, rund 5.300 fehlende verrechenbare medizinische Leistungen wiederherzustellen, und machte zukünftige Backfills und Nachtläufe deutlich sicherer.
Domainnamen, Identifier und interne Implementierungsdetails sind hier generalisiert; Architektur und Engineering-Entscheidungen bleiben erhalten.
Vorher
Das wichtige Problem war die Form der Pipeline. Sie verhielt sich wie eine lange Verarbeitungsspur, in der Datenvolumen, wiederholte Lookups und Fehlerbehandlung einander verstärkten.
Nachher
Der Refactor veränderte den Job von einem fragilen Bulk-Prozess in eine begrenzte, beobachtbare Recovery-Pipeline. Jede Stufe hat nun eine kleinere Verantwortung und eine klarere Fehlergrenze.
Fensterbasierte Terminverarbeitung
Statt den gesamten Terminbereich als eine große Einheit zu verarbeiten, teilt der Job den Zeitraum in konfigurierbare Fenster. Jedes Fenster lädt Termine, prüft vorhandene Leistungen, generiert fehlende Leistungen und fährt danach mit dem nächsten Fenster fort.
Dadurch bleiben Speicherverbrauch und Query-Größe begrenzt. Gleichzeitig werden Backfills einfacher, weil historische Bereiche in vorhersehbaren Scheiben verarbeitet werden können, statt jeden Recovery-Lauf zu einem übergroßen Produktionsevent zu machen.
Run-level Caching
Mehrere teure Werte werden innerhalb eines Laufs über viele Termine hinweg wiederverwendet: Service-Konfiguration, Kostenstellen, Einstellungen für verantwortliche Ärzte, Fallart und Leistungsblock-Metadaten.
Der Refactor führte Run-level Caches für diese Lookups ein. Identische Requests verwenden dasselbe Promise wieder, und fehlgeschlagene Requests werden aus dem Cache entfernt, damit spätere Termine erneut versuchen können, statt einen vergifteten Cache-Eintrag zu übernehmen.
Fehlerisolation
Die wichtigste Reliability-Änderung war, Vorbereitungsfehler von Schreibfehlern zu trennen und beide auf Terminebene zu behandeln.
Vorbereitung umfasst das Laden von Kostenstellen, verantwortlichen Ärztinnen und Ärzten, Fallinformationen und Leistungsblöcken. Schreiben ist die finale GraphQL-Mutation, die die Leistungssession erzeugt. Durch diese Isolation kann der Job einen problematischen Termin überspringen und die übrigen weiter wiederherstellen.
Bekannte recoverbare Leistungsblockfehler werden als Datenqualitätsproblem dieses Termins behandelt, nicht als Grund, den ganzen Lauf aufzugeben. Wenn ein Termin noch valide verrechenbare Blöcke hat, schreibt der Job diese. Wenn keine übrig bleiben, erfasst der Job den Grund.
Observability
Der stabilisierte Job endet mit kategorisierten Zählern statt mit einem vagen Erfolgs- oder Fehlersignal. Dadurch wurde die Recovery-Arbeit messbar und der Job selbst zu einem Diagnosewerkzeug.
Wenn Leistungen nicht generiert werden, kann das Team nun erkennen, ob die Ursache in Termindaten, Stammdaten, Leistungsblock-Gültigkeit, Validierungsverhalten oder dem Write-Pfad liegt.
Warum es gutes Engineering war
Das Ergebnis war ein Job, dem man für den eigentlichen Geschäftsprozess vertrauen konnte, nicht nur für technische Ausführung.
- Begrenzte Workload: Datumsfenster und Query-Chunking machen den Job im normalen Betrieb und bei Backfills sicherer.
- Weniger wiederholte Arbeit: Caches reduzieren doppelte Metadaten- und GraphQL-Aufrufe.
- Kleinerer Fehlerumfang: Ein fehlerhafter Termin verhindert nicht mehr die Recovery unabhängiger Termine.
- Bessere finanzielle Vollständigkeit: Das System findet und schreibt Leistungen, die zuvor liegen geblieben sind.
- Operative Evidenz: Kategorisierte Logs und Zusammenfassungen zeigen, wo Verluste entstehen und was noch bereinigt werden muss.
Impact
Die stabilisierte Pipeline half dabei, rund 5.300 fehlende verrechenbare medizinische Leistungen wiederherzustellen. Wichtiger noch: Sie machte aus einem fragilen Prozess einen wiederholbaren Recovery-Mechanismus, der überwacht, erklärt und sicher erneut ausgeführt werden kann.
Für einen verrechnungsnahen Healthcare-Workflow ist das relevant, weil klinische Aktivität vollständiger in nachgelagerten Systemen erscheint, Finance-Teams weniger stille Lücken manuell klären müssen und Engineers klarere Signale bekommen, wenn Stammdaten oder Validierungsregeln Aufmerksamkeit brauchen.