Staging Ingest Operations Runbook¶
Dieser Block beschreibt nur den operativen Ablauf fuer den separaten Kafka/Ingest-Worker im Staging. Die API bleibt dabei weiter online, weil der Worker als eigener Compose-Service laeuft.
Wann wir den Worker einschalten¶
STAGING_INGEST_ENABLED=truestartet den dedizierteningest-Worker beim naechsten Staging-Deploy.STAGING_INGEST_ENABLED=falsestoppt den Worker wieder und entfernt alte Container aus frueheren Deploys.- Aendere den Wert in den GitHub Actions Variablen und starte den Workflow
Deploy Stagingerneut auf demdevelopment-Branch.
Replicas hoch- und runterfahren¶
STAGING_INGEST_REPLICASsteuert die Anzahl der Worker-Instanzen im Staging-Deploy.- Starte normal mit
1. - Erhoehe den Wert, wenn sich CDC-Backlog oder Catch-up sichtbar aufbauen.
- Reduziere den Wert wieder, wenn die Last sinkt oder wir nur eine einzelne Instanz brauchen.
- Mehrere Replicas sind unkritisch, weil sie sich den gleichen Kafka Consumer Group State teilen.
Verifikation nach dem Deploy¶
Pruefe nach jedem Deploy diese Punkte:
docker compose ps backend ingest
docker compose logs --tail 200 ingest
curl -sS http://127.0.0.1:8080/healthz | jq '.components.ingest'
curl -sS http://127.0.0.1:8080/api/admin/diagnostics/summary | jq '.ingest'
Erwartung:
- status unter components.ingest ist up
- workerState ist running
- lastErrorMessage ist leer
- heartbeatAt und lastProcessedAt aktualisieren sich
- catchUpState ist je nach Lage live oder kontrolliert catching_up
- lagSampledAt wird frisch geschrieben und lagErrorMessage bleibt leer
- totalLag, maxTopicLag und lagTopics zeigen, ob echter Rueckstau vorliegt oder nur normaler Live-Betrieb
- der Admin-Bereich zeigt den Ingest-Status nicht mehr als pauschalen Fehler, sondern als echte Worker-Info
Wenn der Worker laeuft, aber die Daten nicht weiter vorankommen, dann zuerst Logs und Health pruefen, danach die Kafka-/Debezium-Strecke getrennt betrachten.
Wichtig fuer Releases mit Datenbankaenderungen:
Deploy Stagingfuehrt vor dem Restart automatischnpm run prisma:migrate:deployim Backend-Image aus.- Dadurch werden neue Prisma-Migrationen zusammen mit dem Release auf das Staging-Schema angewendet.
- Wenn dieser Schritt scheitert, bleibt das Deploy bewusst stehen, bevor die neuen Container live gehen.
Backfill und Reprocessing¶
Fuer gezielte Rueckverarbeitung nutzen wir den Backfill-Command im Backend:
cd targetshot/backend
npm run ingest:backfill -- 1234:5678 1234:6789
Nutzliche Optionen:
--group=<id>verwendet eine stabile Consumer Group fuer Lag-Beobachtung--new-groupstartet einen frischen Replay-Lauf ab Offset 0
Empfohlener Ablauf fuer groessere Reprocessing-Faelle:
- Live-Worker bei Bedarf kurz deaktivieren oder auf
1Replicas lassen. - Backfill mit einer klar benannten Gruppe starten.
- Ergebnis in Mirror-DB, Kafka-Topic und Admin-Diagnose pruefen.
- Den normalen Worker wieder aktivieren bzw. die Replicas hochziehen.
Fuer die historische Rueckverarbeitung der Schuetzen-Stammdaten steht zusaetzlich der manuelle GitHub-Workflow Replay Shooter Master Data zur Verfuegung.
Empfohlene Eingaben:
club_ids: zum Beispiel413067group_id: Standardtargetshot-shooter-backfillfresh_group=true: erzwingt einen frischen Replay-Lauf ab Offset0
Der Workflow startet einen einmaligen Backend-Container mit node dist/ingest/backfillShooters.js ... und nutzt dabei die bestehende Staging-.env.
Incident-Matrix fuer Source-Drift und Rejects¶
Die Ingest-Health unterscheidet jetzt bewusst zwischen normalem Betrieb, frischen Vertragsabweichungen und echter Quarantaene:
workerState=running+catchUpState=live: normaler Live-BetriebadmissionState=rejecting: frische, wiederholte Contract-Rejects; einzelne fehlerhafte Events werden verworfen, aber der Worker verarbeitet weitersourceDriftState=suspected: es gibt ein frisches Drift-Signal, bevor bereits ein voller Incident offen istadmissionState=quarantined: derselbe fehlerhafte Pfad wurde mehrfach in kurzer Zeit abgelehnt; der Vorfall ist jetzt operativ ein IncidentincidentState=recovered: der vormals fehlerhafte Pfad wurde spaeter wieder mit passender Herkunft akzeptiert
Diese Signale erscheinen an drei Stellen:
GET /healthzuntercomponents.ingestadmin-portalinConnectorsbeim Shared-Ingest-Block des Host-Dialogsadmin-portalinDiagnosticsund in den Dashboard-Warnungen
Wichtige Felder fuer die Einordnung:
lastContractRejectReasonlastContractRejectTopiclastContractRejectEntitysourceDriftDetailrejectBurstCountquarantineSincequarantineTopicquarantineClubIdquarantineEntityquarantineDetail
Vorgehen bei rejecting oder sourceDriftState=suspected¶
Wenn der Worker noch laeuft, aber frische Rejects oder Drift-Hinweise auftauchen:
- Im
admin-portalden betroffenen Club-Host oeffnen undsourceDriftDetail,lastContractRejectReason, Topic und Entity notieren. - In
/healthzoder den Worker-Logs bestaetigen, ob der Fehler von einem einzelnen Event oder von einer durchgehenden Serie kommt. - Am Producer-/Connector-Pfad pruefen:
- passt
source_topiczur Entitaet? - passt
source_club_idzum Topic-Scope? - gibt es widerspruechliche Header-/Payload-Herkunft?
- Solange noch keine Quarantaene vorliegt, den Worker weiterlaufen lassen und nur den fehlerhaften Producer-Pfad korrigieren.
- Nach der Korrektur aktiv beobachten, ob
sourceDriftStatewieder aufrecoveredodernonefaellt.
Faustregel:
suspectedoderrejectingist noch kein automatischer Rollback-Fall.- Erst wenn die gleiche Abweichung wiederholt auftritt oder produktiv mehrere Clubs betreffen koennte, wird der Incident wie eine Quarantaene behandelt.
Vorgehen bei admissionState=quarantined¶
Bei Quarantaene ist der Herkunftsvertrag mehrfach verletzt worden. Dann gilt:
- Den betroffenen Producer-/Connector-Pfad zuerst stoppen oder korrigieren.
- Keine grossflaechige Replay-Aktion starten, solange der Scope-Fehler noch offen ist.
quarantineTopic,quarantineClubId,quarantineEntityundquarantineReasonim Incident festhalten.- Danach entscheiden:
- nur der betroffene Pfad war falsch: Worker kann weiterlaufen, sobald wieder gueltige Events kommen
- mehrere Pfade oder hoher Druck auf dem Cluster:
STAGING_INGEST_REPLICASreduzieren oderSTAGING_INGEST_ENABLED=falsesetzen und neu deployen - Erst nach erfolgreicher Scope-Korrektur gezielt reprocessen.
Ein recovered-Zustand bedeutet:
- der Worker hat fuer denselben Pfad spaeter wieder gueltige Herkunft gesehen
- das ist ein gutes Signal, ersetzt aber nicht die fachliche Kontrolle, ob ein Replay noetig ist
Reprocessing-Vertrag nach einer Korrektur¶
Nach einem Source- oder Mapping-Fehler wird immer in dieser Reihenfolge gearbeitet:
- Ursache am Producer-/Connector beheben
- mit
/healthzbestaetigen, dass keine neue Reject-Serie mehr entsteht - Reprocessing gezielt fuer den betroffenen Datenschnitt starten
- Ergebnis im Zielmodell validieren
- erst danach eventuell Replicas wieder hochziehen
Fuer Treffer-/Scheiben-bezogene Rueckverarbeitung:
cd targetshot/backend
npm run ingest:backfill -- --group=targetshot-reprocess-incident 413067:899822614
Fuer einen frischen Replay-Lauf ohne alten Consumer-Offset:
cd targetshot/backend
npm run ingest:backfill -- --group=targetshot-reprocess-incident --new-group 413067:899822614
Fuer historische Schuetzen-Stammdaten:
cd targetshot/backend
npm run ingest:backfill-shooters -- --group=targetshot-shooter-reprocess --new-group 413067
Nach jedem Reprocessing muessen mindestens diese Punkte gruen sein:
workerState=runningcatchUpStategeht wieder aufliveoder faellt kontrolliert auscatching_upzuruecksourceDriftStatebleibt aufnoneoderrecovered- keine neuen Contract-Rejects fuer denselben Pfad
- das fachliche Zielmodell wurde wirklich aktualisiert
Rollback¶
Wenn eine neue Ingest-Version Probleme macht:
STAGING_INGEST_ENABLED=falsesetzen und den Staging-Deploy erneut ausfuehren.- Wenn nur zu viel Druck auf dem Cluster entsteht,
STAGING_INGEST_REPLICASauf1reduzieren. - Danach Logs, Health und Mirror-DB erneut validieren.
- Vor einem erneuten Einschalten pruefen, ob noch ein offener Source-Drift-/Quarantaene-Kontext besteht.
- Erst wenn der Ingest-Pfad wieder stabil ist, den Worker wieder hochfahren.
Wichtig: - Der Worker ist absichtlich vom API-Container getrennt. - Ein Rollback kann deshalb den Ingest sauber stoppen, ohne dass die API neu gebaut werden muss. - Ein Rollback ersetzt keine spaetere gezielte Rueckverarbeitung; fehlende Daten muessen danach bewusst nachgezogen werden.
Kurzcheck fuer Operatoren¶
- Ist der Worker aktiv?
- Meldet
/healthzden Worker alsupundrunning? - Wieviele Replicas laufen?
- Stehen
lastProcessedAtundheartbeatAtnoch? - Ist
lagSampledAtfrisch und bleibtlagErrorMessageleer? - Wie gross sind
totalLagund die auffaelligstenlagTopics? - Gibt es
sourceDriftState, frische Rejects oder eine laufende Quarantaene? - Ist ein neuer Fehler in
lastErrorMessageaufgetaucht? - Wurde eine gegebene Rueckverarbeitung wirklich im Mirror-DB-Stand sichtbar?
- Wurde nach einem Incident auch das fachliche Zielmodell wieder geprueft?
Wenn diese Punkte sauber sind, ist der Staging-Ingest aus Ops-Sicht gesund.