TEKO Schweizerische FachschuleEAI IntegrationslaborUnterricht 3 von 4 · Orthanc
Live-Labor

Unterricht 03 · Spitalintegration

Orthanc, Events
& Resilienz

Mission: Eine vollständig synthetische Bildstudie wird über eine öffentliche Lern-API als Job angenommen, intern gegen Orthanc geprüft und trotz temporärer Fehler nachvollziehbar verarbeitet – ohne Patientendaten, Verlust oder Doppelwirkung.

OrthancDICOMEventQueueRetryDLQ & ReplayIdempotenz8 Übungen
Verbindliche Datenschutzgrenze: Verwende ausschließlich die veröffentlichten Demo-Referenzen. Die API akzeptiert keine Namen, Geburtstage, echten Fallnummern, frei erfundenen DICOM-UIDs oder Bilddateien. Orthanc bleibt im internen Docker-Netz; öffentlich sichtbar ist nur eine schmale, bereinigte Lern-API.
Ablauf

Vier Stunden vom Modell bis zum Störungsnachweis

Theorie & FallDICOM, Events, Queue, Identitäten
Gemeinsame Demo202, Status-URL und Orthanc-Prüfung
Live-Labor8 Aufgaben mit echten HTTP-Aufrufen
Störung & TransferDLQ, Replay, Quiz, Diskussion
Lernpfad

Fallstudie und Theorie zum Nachschlagen

Datenfluss

Kleine öffentliche Nachricht, begrenzter interner Zugriff

Lernende
synthetische Referenz
Lern-API
Validierung · Queue · Worker
Orthanc intern
Metadaten-Lookup

1. Annahme

POST /lab/api/v1/imaging-jobs prüft Body und Header. Bei einer neuen gültigen Anfrage antwortet die API mit 202 Accepted, Job-ID und Status-URL.

2. Verarbeitung

Ein Worker liest den Job, übersetzt die Demo-Referenz intern in eine synthetische StudyInstanceUID und fragt Orthanc gezielt über POST /tools/find ab.

3. Nachweis

Der Job endet in completed, retrying oder dead_letter. Verlauf, Versuchszähler und Correlation-ID machen die Entscheidung sichtbar.

Metapher & Zeichnung

Die digitale Rohrpost im Spital

Rohrpostmetapher für einen asynchronen Orthanc-Job Eine radiologische Station legt eine kleine beschriftete Kapsel in die Rohrpost. Eine Weiche puffert und verteilt sie an den Metadaten-Worker. Temporäre Störungen führen in eine Warteschleife, fachlich nicht verarbeitbare Kapseln in ein kontrolliertes Quarantänefach. Eine Laufnummer begleitet den gesamten Weg. Radiologie Demo-Referenz Kapsel: Job Rohrpost-Weiche Annahme · Puffer Zustellversuche Metadaten-Labor Worker prüft internes Orthanc Resultat Status & Nachweis Warteschleife Retry mit Backoff Quarantänefach DLQ, dann Replay Laufnummer: corr-imaging-l3-001
Die Kapsel enthält nur die für den Transport nötige Demo-Referenz. Die Correlation-ID entspricht der Laufnummer; das Quarantänefach steht für eine sichtbare DLQ und nicht für Löschen.

Was die Metapher erklärt

Absender und Empfänger müssen nicht gleichzeitig bereitstehen. Eine Kapsel kann gepuffert, erneut zugestellt und anhand einer Laufnummer verfolgt werden. Eine problematische Sendung wird kontrolliert isoliert, geprüft und erst nach einer Korrektur erneut in den Ablauf gegeben.

Wo die Metapher endet

Digitale Nachrichten können identisch kopiert und parallel zugestellt werden. Eine technische Bestätigung kann ausfallen, obwohl die Fachwirkung bereits eingetreten ist. Das Labor verwendet außerdem eine begrenzte Queue im Arbeitsspeicher; bei einem Neustart bleibt sie nicht erhalten. Für Produktion wären ein persistenter Broker, validierte klinische Verfahren und strengere Betriebszusagen nötig.

Theorie

Vierzehn Bausteine für einen belastbaren Ablauf

Definition · Folge · Entscheidung
1. DICOM-Studie und Orthanc

DICOM strukturiert medizinische Bildobjekte in Patient, Study, Series und Instance. Orthanc speichert und findet diese Ressourcen, besitzt aber lokale technische IDs. Die öffentliche Lern-API nimmt keine Bilddateien entgegen. Sie übersetzt eine veröffentlichte Demo-Referenz erst intern in eine synthetische StudyInstanceUID und fragt Orthanc gezielt ab.

2. Öffentliche Sicherheitsgrenze

Der Browser oder curl spricht ausschließlich /lab/... an. Die Lern-API erlaubt nur wenige feste Felder, begrenzt Body-Größe und Antwortdaten und leitet keine beliebigen Orthanc-Routen weiter. Orthanc-Zugangsdaten, DICOM-Port und Verwaltungsoberfläche bleiben im privaten Container-Netz.

3. Event, Command und Message

Ein Event beschreibt eine eingetretene Tatsache, zum Beispiel imaging.metadata.lookup.completed. Ein Command fordert Arbeit an, hier sinngemäß imaging.metadata.lookup.requested. Die Message ist die transportierte Einheit mit Daten und technischen Metadaten. Klare Namen zeigen, ob etwas bereits geschehen ist oder erst geschehen soll.

4. Kleine Nachricht statt Bildkopie

Die Queue transportiert Demo-Referenz, Quellspital, Zweck, Correlation-ID und Idempotency-Key. PixelData, PatientName und echte Identitäten fehlen bewusst. Der Worker holt die nötige Information intern aus dem verantwortlichen System. Das vermindert Datenkopien, Queue-Größe und Schutzfläche.

5. 202 Accepted und Status-URL

202 Accepted bedeutet: Der Request wurde angenommen, aber die fachliche Verarbeitung ist noch nicht abgeschlossen. Die Response liefert jobId, statusUrl, Retry-After und Correlation-ID. Der Client fragt später den Zustand ab, anstatt die HTTP-Verbindung bis zum Orthanc-Ergebnis offen zu halten.

6. Queue, Worker und Bestätigung

Die Queue trennt Annahme und Ausführung zeitlich. Der Worker nimmt einen Job, markiert processing, führt die interne Abfrage aus und schreibt Resultat oder Fehler. Im Kurs ist die Queue bewusst klein und im Arbeitsspeicher. Das macht das Muster sichtbar, ist aber keine Zusage für Persistenz oder Hochverfügbarkeit.

7. At-least-once statt magischem Exactly-once

Ein reales Nachrichtensystem kann eine Message erneut zustellen, wenn die Bestätigung verloren geht. Darum darf die gleiche Meldung keine zweite Fachwirkung erzeugen. „Genau einmal transportiert“ ist über mehrere Systeme schwer sicherzustellen; „genau einmal wirkender Effekt“ durch Idempotenz ist die wichtigere fachliche Garantie.

8. Technischer und fachlicher Fehler

Ein vorübergehend nicht erreichbares Orthanc ist ein technischer, potenziell retrybarer Fehler. Eine unzulässige Kombination aus Studie und Quellspital oder eine verletzte Metadatenregel ist fachlich und wird ohne Korrektur nicht besser. Die Fehlerklasse bestimmt Retry, Ablehnung oder DLQ.

9. Retry, exponentieller Backoff und Obergrenze

Der Labor-Worker wartet nach einem simulierten temporären Fehler und versucht die Verarbeitung erneut. Produktionssysteme verwenden begrenzte Versuche, zunehmende Abstände und häufig Jitter. Sofortige Endlosschleifen verstärken den Ausfall und verdecken die eigentliche Ursache.

10. Dead-Letter Queue

Ein nicht automatisch lösbarer Job landet als dead_letter mit Verlauf, Fehlercode, Versuchszahl und Correlation-ID in einer separaten Liste. Eine DLQ ist ein Nachbearbeitungsfach. Sie braucht Besitzer, Alarm und Frist; ohne Bearbeitung wäre sie lediglich ein unsichtbarer Friedhof.

11. Replay nach nachgewiesener Korrektur

Die Replay-Route akzeptiert nur Jobs im Zustand dead_letter und verlangt {"correctionApplied":true}. Damit formuliert die API eine Betriebsregel: erst Ursache klären, dann die unveränderte Arbeit neu einplanen. Die gesamte History bleibt für den Unterricht nachvollziehbar.

12. Idempotency-Key

Beim ersten POST reserviert die API den Key für genau diesen Request. Derselbe Key mit demselben Body gibt den bestehenden Job zurück und setzt idempotentReplay auf true. Derselbe Key mit einem anderen Body erzeugt 409 Conflict. So wird eine versehentliche Doppelwirkung sichtbar verhindert.

13. Correlation-ID und Observability

Die Correlation-ID begleitet Annahme, Job-History und simulierte Webhook-Zustellung. Sie beantwortet „Was geschah mit diesem Lauf?“. Job-ID, Idempotency-Key und Correlation-ID haben verschiedene Aufgaben: Objekt adressieren, Doppelwirkung verhindern und Stationen verbinden.

14. Reihenfolge, Last und Datenschutz

Asynchrone Systeme müssen mit Warteschlangenlänge, später Verarbeitung und möglicher Reihenfolgeänderung umgehen. Gleichzeitig dürfen Logs, Events und DLQ keine unnötigen Gesundheitsdaten vervielfachen. Das Labor akzeptiert deshalb nur feste synthetische Referenzen und gibt ausdrücklich containsPatientData: false zurück.

Eventvertrag

Eine Job-Nachricht ohne Patientendaten

Nach der Annahme verwaltet die Lern-API intern einen Job in dieser Form. Die Identitäten sind technisch und synthetisch. Weder Patienteneigenschaften noch Bilddaten gehören in diesen Vertrag.

{
  "jobId": "job-7f15d8a0c61e4b21",
  "type": "imaging.metadata.lookup.requested",
  "status": "queued",
  "correlationId": "corr-imaging-l3-001",
  "idempotencyKey": "l3-demo-ab-001",
  "request": {
    "studyReference": "STUDY-DEMO-BERN-001",
    "sourceHospitalId": "spital-bern",
    "purpose": "teaching-validation",
    "simulation": "success"
  }
}
Laborfeld: simulation dient nur dazu, Happy Path, temporären Fehler und Fachfehler reproduzierbar auszulösen. In einem produktiven Ereignis würde kein Absender den gewünschten Fehler anfordern; Fehler entstehen aus dem realen Systemzustand.
Öffentliche Referenz

Diese Pfade sind wirklich erreichbar

Im Live-Labor öffnen →
GET/lab/healthzLiveness der Lern-API ohne Abhängigkeitsprüfung
GET/lab/readyzReadiness inklusive internem Orthanc
GET/lab/api/v1/pacs/statusbereinigter Orthanc-Status
GET/lab/api/v1/demo-studieserlaubte synthetische Studienreferenzen
POST/lab/api/v1/imaging-jobsasynchronen Job annehmen
GET/lab/api/v1/jobsJobs und Verlauf lesen
POST/lab/api/v1/dead-letters/{jobId}/replaynach Korrektur neu einplanen
GET/lab/api/v1/webhook-deliverieserfolgreiche simulierte Zustellungen
GET/lab/openapi.jsonOpenAPI-3.1-Vertrag

Basis-URL: Öffentlich https://teko.algorithma.app, lokal http://localhost:3190. Pfade und JSON-Verträge sind gleich. Die öffentliche Instanz wird gemeinsam genutzt; verwende deshalb eigene Idempotency- und Correlation-IDs.

Praxis

Übungslabor mit der Live-API

🟢 Pflicht · 🔵 Plus · 🟣 Challenge
Pflicht15 min

1. Dienst und Orthanc-Bereitschaft unterscheiden

Prüfe zuerst Liveness, dann Readiness und schließlich den sanitiserten PACS-Status. Vergleiche Statuscode und Body. Liveness kann erfolgreich sein, obwohl die Abhängigkeit nicht bereit ist.

curl -i https://teko.algorithma.app/lab/healthz
curl -i https://teko.algorithma.app/lab/readyz
curl -i https://teko.algorithma.app/lab/api/v1/pacs/status
curl -s https://teko.algorithma.app/lab/openapi.json
Abnahmekriterium

Du kannst erklären, weshalb /healthz nur den Prozess prüft und /readyz zusätzlich den internen Orthanc-Adapter berücksichtigt.

Erwartung: Im betriebsbereiten Stack liefern alle Statusabfragen 200. Bei Orthanc-Ausfall bleibt /healthz 200, während /readyz und der PACS-Status 503 melden.
Pflicht15 min

2. Synthetische Studien und Datenminimierung prüfen

Lies die erlaubten Demo-Referenzen. Suche gezielt nach Feldern, die vorhanden sind, und nach Patientendaten, die bewusst fehlen. Wähle für die folgenden Aufgaben die Bern-Studie.

curl -s https://teko.algorithma.app/lab/api/v1/demo-studies
Kontrollauftrag
  • Welche Werte verbinden Studie, Spital und Modalität?
  • Warum wird keine StudyInstanceUID öffentlich ausgegeben?
  • Was beweist containsPatientData – und was nicht?
Erwartung: Öffentlich erscheinen studyReference, sourceHospitalId, Modalität, Beschreibung und containsPatientData:false. Die technische Kennzeichnung ersetzt keine Datenschutzprüfung, dokumentiert aber die Absicht des Vertrags.
Pflicht25 min

3. Happy Path asynchron starten und verfolgen

Ersetze ab in Key und Correlation-ID durch dein Kürzel. Sende einen gültigen Job. Notiere HTTP-Status, Location, jobId, statusUrl und correlationId. Rufe danach die zurückgegebene Status-URL auf, bis der Job abgeschlossen ist.

curl -i -X POST https://teko.algorithma.app/lab/api/v1/imaging-jobs \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: l3-ab-happy-001' \
  -H 'X-Correlation-ID: corr-l3-ab-happy-001' \
  -d '{
    "studyReference":"STUDY-DEMO-BERN-001",
    "sourceHospitalId":"spital-bern",
    "purpose":"teaching-validation",
    "simulation":"success"
  }'

curl -s https://teko.algorithma.app/lab/api/v1/jobs/JOB_ID
Abnahmekriterium

Der erste POST liefert 202. Der Statusverlauf enthält mindestens queued, processing und completed; das Resultat nennt Lookup, Modalität, Trefferzahl und containsPatientData:false.

Hinweis: Kopiere die echte jobId aus der Response. Ein 202 beweist nur die Annahme; erst der GET auf die Status-URL zeigt den fachlichen Abschluss.
Pflicht25 min

4. Temporären Orthanc-Fehler und Retry beobachten

Starte einen neuen Job mit transient_failure und eigenem Key. Lies danach den Jobverlauf. Der erste Worker-Versuch simuliert eine vorübergehende Störung; der nächste Versuch darf nach Backoff erneut prüfen.

curl -i -X POST https://teko.algorithma.app/lab/api/v1/imaging-jobs \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: l3-ab-retry-001' \
  -H 'X-Correlation-ID: corr-l3-ab-retry-001' \
  -d '{
    "studyReference":"STUDY-DEMO-ZUERICH-001",
    "sourceHospitalId":"spital-zuerich",
    "purpose":"metadata-audit",
    "simulation":"transient_failure"
  }'

curl -s https://teko.algorithma.app/lab/api/v1/jobs/JOB_ID
Beobachtungsauftrag

Finde in history den Zustand retrying, den Grund mit with_backoff sowie mindestens zwei Verarbeitungsversuche. Begründe, warum dieser Fehler wiederholt werden darf.

Erwartung: Der simulierte Fehler tritt nur im ersten Zyklusversuch auf. Bei verfügbarem internem Orthanc endet der Job danach in completed und attemptCount ist mindestens 2.
Plus25 min

5. Fachfehler gezielt in die DLQ leiten

Erzeuge einen reproduzierbaren fachlichen Metadatenfehler. Prüfe den Job und anschließend die DLQ. Vergleiche Fehlercode, retryable, History und Versuchszähler mit Aufgabe 4.

curl -i -X POST https://teko.algorithma.app/lab/api/v1/imaging-jobs \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: l3-ab-dlq-001' \
  -H 'X-Correlation-ID: corr-l3-ab-dlq-001' \
  -d '{
    "studyReference":"STUDY-DEMO-LUZERN-001",
    "sourceHospitalId":"spital-luzern",
    "purpose":"routing-check",
    "simulation":"business_failure"
  }'

curl -s https://teko.algorithma.app/lab/api/v1/jobs/JOB_ID
curl -s https://teko.algorithma.app/lab/api/v1/dead-letters
Abnahmekriterium

Der Job erreicht dead_letter mit metadata_rule_rejected, retryable:false und ohne eine technische Retry-Schleife.

Begründung: Die simulierte Metadatenregel ändert sich nicht durch Warten. Der Fall muss isoliert und fachlich geklärt werden.
Plus25 min

6. Nach Korrektur kontrolliert wiederholen

Übernimm die Job-ID aus Aufgabe 5. Spiele nur diesen DLQ-Fall erneut ab und bestätige ausdrücklich, dass die Ursache als korrigiert gilt. Verfolge danach dieselbe Job-ID bis zum neuen Endzustand.

curl -i -X POST \
  https://teko.algorithma.app/lab/api/v1/dead-letters/JOB_ID/replay \
  -H 'Content-Type: application/json' \
  -H 'X-Correlation-ID: corr-l3-ab-dlq-001' \
  -d '{"correctionApplied":true}'

curl -s https://teko.algorithma.app/lab/api/v1/jobs/JOB_ID
Kontrollfragen
  • Warum bleibt die Job-ID gleich?
  • Welche History-Einträge beweisen DLQ und Replay?
  • Was antwortet die API bei correctionApplied:false?
Erwartung: Replay antwortet 202 und plant denselben Job neu ein. Die History enthält manual_replay_after_correction; bei betriebsbereitem Orthanc endet der Fall in completed.
Plus30 min

7. Doppelzustellung und Idempotenz beweisen

Sende exakt denselben Happy-Path-Request aus Aufgabe 3 nochmals mit demselben Idempotency-Key. Ändere anschließend bei gleichem Key nur purpose. Dokumentiere beide Responses.

# 1. Exakt Body und Key aus Aufgabe 3 wiederholen:
curl -i -X POST https://teko.algorithma.app/lab/api/v1/imaging-jobs \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: l3-ab-happy-001' \
  -H 'X-Correlation-ID: corr-l3-ab-repeat-001' \
  -d '{
    "studyReference":"STUDY-DEMO-BERN-001",
    "sourceHospitalId":"spital-bern",
    "purpose":"teaching-validation",
    "simulation":"success"
  }'

# 2. Gleicher Key, aber anderer Body → Konflikt erwartet:
curl -i -X POST https://teko.algorithma.app/lab/api/v1/imaging-jobs \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: l3-ab-happy-001' \
  -H 'X-Correlation-ID: corr-l3-ab-conflict-001' \
  -d '{
    "studyReference":"STUDY-DEMO-BERN-001",
    "sourceHospitalId":"spital-bern",
    "purpose":"metadata-audit",
    "simulation":"success"
  }'
Abnahmekriterium

Die identische Wiederholung liefert den bestehenden Job, HTTP 200 und idempotentReplay:true. Derselbe Key mit verändertem Body liefert HTTP 409 idempotency_conflict.

Lernpunkt: Die API vergleicht nicht nur den Key, sondern bindet ihn an den validierten Request. Dadurch kann derselbe Schlüssel nicht versehentlich eine andere Arbeit bezeichnen.
Challenge30 min

8. Einen Lauf nur mit der Correlation-ID rekonstruieren

Wähle eine Correlation-ID aus den vorherigen Aufgaben. Suche sie in Jobliste, Job-History und erfolgreichen Webhook-Zustellungen. Erstelle eine kurze Incident-Zeitleiste mit Zeit, Station, Zustand, Versuch und Ergebnis.

curl -s 'https://teko.algorithma.app/lab/api/v1/jobs?limit=100'
curl -s 'https://teko.algorithma.app/lab/api/v1/webhook-deliveries?limit=100'
curl -s https://teko.algorithma.app/lab/api/v1/jobs/JOB_ID
Abnahmekriterium

Die Zeitleiste trennt Job-ID, Idempotency-Key und Correlation-ID korrekt. Sie enthält keine Patientendaten und erklärt, weshalb nur erfolgreiche beziehungsweise erfolgreich wiederholte Jobs im Webhook-Protokoll erscheinen.

Muster: 202 angenommen → queued → processing → optional retrying/dead_letter → Replay → completed → Webhook 204. Die genauen Zeitstempel stammen aus history und deliveredAt.
Diskussion

Welche Garantie ist im Spitalfall wirklich belastbar?

  • Warum ist 202 Accepted kein Beweis für eine abgeschlossene Orthanc-Abfrage?
  • Welche betrieblichen Zusagen fehlen der In-Memory-Queue des Labors für einen produktiven Spitalprozess?
  • Wann ist ein Retry hilfreich, wann verstärkt er die Störung?
  • Warum ist ein idempotenter fachlicher Effekt realistischer als ein globales „Exactly once“?
  • Wer muss eine DLQ überwachen, und welche Bearbeitungsfrist wäre im jeweiligen klinischen Kontext vertretbar?
  • Welche Metadaten braucht der Worker tatsächlich – und welche wären nur ein unnötiges Datenschutzrisiko?
Moderationsziel: Die Studierenden sollen technische Demo-Garantien von produktiven klinischen Anforderungen trennen und für jede Fehlerklasse eine begründete Reaktion nennen.
Mini-Quiz

Fehler klassifizieren, bevor man handelt

Ein Job verletzt reproduzierbar eine fachliche Metadatenregel. Was ist die beste erste Reaktion?

Ergebnis des Tages
Du hast einen synthetischen Orthanc-Metadatenjob über eine echte öffentliche API angenommen, Status und Correlation verfolgt, technischen Retry von Fachfehler unterschieden, DLQ und Replay ausgeführt sowie Idempotenz praktisch bewiesen.