Brio-IO Communication Server

Konzepte

Wie Brio-IO aufgebaut ist: Channels und Connectoren, die Pipeline, kanonisches HL7v2-XML, Git als Konfigurationsquelle — und Branches mit Shadowing und Vergleich, inklusive ihrer heutigen Grenze.

Stand: Beispiele geprüft gegen brio-server fa237ec7ad

Dieses Kapitel erklärt die Bausteine, auf die alle anderen Kapitel verweisen. Es beschreibt den Stand, der heute läuft — nicht den Plan.

Channel und Connector

Ein Channel ist eine Verarbeitungsstrecke. Er hat einen Source-Connector, eine Kette von Verarbeitungsschritten und eine oder mehrere Destinations:

Source-Connector

Filter        (pro Nachricht: verarbeiten oder verwerfen)

Transformer   (Nachricht umschreiben)

Destination-Connector(s)

Connectoren sind eigenständige Objekte, keine Unterfelder eines Channels. Sie werden getrennt angelegt und im Channel referenziert — derselbe http-listener kann so von mehreren Channels genutzt werden, und ein Connector lässt sich unabhängig vom Channel testen und ändern.

Jeder Connector hat ein Protokoll (mllp-listener, file-reader, http-sender, …) und einen Satz typisierter Properties. Welche Protokolle es gibt und welche Properties sie kennen, steht in der Connector-Referenz.

Die Nachricht durchläuft Stufen — und alle bleiben sichtbar

Brio-IO speichert eine Nachricht nicht nur in ihrem Endzustand, sondern in Stufen: RAW (wie sie ankam), TRANSFORMED (nach Filter und Transformer), SENT (was rausging). Dazu kommen Zustände, die sonst gerne unsichtbar bleiben:

  • FILTERED — eine Nachricht, die ein Filter verworfen hat. Sie erscheint als eigene Zeile, statt spurlos zu verschwinden.
  • ERROR — die Verarbeitung ist gescheitert; der Grund steht in den Hinweisen zur Nachricht.
  • SHADOW_SENT — die Nachricht lief in einem Shadow-Branch (siehe unten).

Jede Nachricht trägt außerdem eine Herkunft (origin), die sagt, aus welchem Zweig sie stammt. Das ist der Grund, warum Shadow-Verkehr die Kennzahlen des Live-Channels nicht verfälscht.

Kanonisches XML: eine Nachricht, eine Form

Sobald eine HL7v2-Nachricht hereinkommt, überführt Brio-IO sie in eine kanonische XML-Repräsentation. Skripte arbeiten auf dieser Form, nicht auf dem rohen ER7-String mit seinen Pipes und Zirkumflexen.

Zwei Eigenschaften dieser Form sind wichtig, weil beide historische Fehler korrigieren:

Underscores statt Punkte. In der klassischen Mirth-Welt heißt das Feld PID.5 — und der Punkt ist in jeder Programmiersprache der Zugriffsoperator. Deshalb muss man dort mit String-Brackets arbeiten. Brio-IO trennt die Ebenen mit Underscore (PID_5), also sind Element-Namen normale Bezeichner.

Komponenten positional durchnummeriert. Eine Komponente heißt nach ihrer Position, nicht nach ihrem HL7-Datentyp:

<PID>
  <PID_3>
    <PID_3_1>12345</PID_3_1>
    <PID_3_4>MRN</PID_3_4>
  </PID_3>
  <PID_5>
    <PID_5_1>Schmidt</PID_5_1>
    <PID_5_2>Hans</PID_5_2>
  </PID_5>
</PID>

PID_5_1 ist der Nachname — Feld PID-5, Komponente 1. Genau die Nummerierung, die HL7 beschreibt und die ein Mirth-Praktiker im Kopf hat.

Für Bestandsskripte wichtig: Eine Zwischenfassung von Brio-IO benannte Komponenten nach ihrem Datentyp (PID_5XPN_1FN_1). Diese Pfade funktionieren heute nicht mehr — sie liefern still einen leeren String. Beim Deployment eines Channels warnt Brio-IO namentlich, wenn ein Skript noch solche Datentyp-Pfade enthält. Der Grund für die laute Warnung statt eines stillen Alias: zwei gleichzeitig gültige Schreibweisen waren genau das Problem, das dieser Umbau beendet hat.

Escape-Sequenzen (\S\, \T\, …) bleiben in der XML verbatim stehen. Wer sie im Skript auflösen oder erzeugen will, nutzt escapeHl7/unescapeHl7 — siehe Transformer-Handbuch.

Drei Skript-Engines, ein Satz Built-ins

Filter und Transformer sind Skripte. Brio-IO betreibt drei Engines parallel; die Engine wählst du pro Skript, nicht pro Channel:

EngineKennungSpracheRolle
GroovygroovyApache GroovyStandard für neue Skripte
GraalJSjs-modernmodernes JavaScriptfür alle, die lieber JS schreiben
Rhinojs-legacyJavaScript mit E4Xnur für importierte Mirth-Skripte

Die Built-ins sind in allen Engines dieselben: msg, xml, channelMap, sourceMap, responseMap, globalMap, globalChannelMap, tmp, logger, xslt. Skripte werden beim Deployment kompiliert, nicht bei jeder Nachricht.

Details und Beispiele: Transformer-Handbuch.

Git ist die Konfigurationsquelle

Die Konfiguration eines Brio-IO-Servers — Channels, Connectoren, Skripte, Code-Templates — liegt nicht in einer Datenbanktabelle, sondern in einem Git-Repository, das der Server selbst führt (eingebettetes JGit, ein optionales Remote ist möglich).

Das ist keine Kosmetik, sondern der Grund für mehrere Eigenschaften, die man sonst nachbauen müsste:

  • Jede Änderung hat einen Commit. Wer, wann, was — ohne separates Audit-Feature.
  • Zurückrollen heißt zurückrollen, nicht „Backup einspielen”.
  • Branches sind echte Git-Branches — und damit die Grundlage des nächsten Abschnitts.

Wo das Repository liegt, steuert brio.config.git.local-path; siehe Betrieb.

Branches: Shadowing und Vergleich

Eine Konfigurationsänderung ist in der Integration selten harmlos: Ein geänderter Transformer trifft echten Traffic, und ob er das Richtige tut, merkt man klassisch erst hinterher. Brio-IO adressiert das mit Branches.

Shadowing. Ein Branch kann den echten Traffic des laufenden Channels beobachten und die Pipeline auf einer Live-Kopie ausführen — ohne ein echtes Ziel anzurufen. Die Ergebnisse landen als SHADOW_SENT im Message-Browser, sauber über origin vom Live-Verkehr getrennt.

Vergleich. Der Vergleich stellt Nachricht für Nachricht gegenüber, was main und der Branch produziert haben, und fällt ein Urteil:

UrteilBedeutung
IDENTICALBranch erzeugt dasselbe Ergebnis wie main
DIFFERENTdie Ergebnisse weichen ab — Seite an Seite ansehbar
NO_PAYLOAD_STOREDder Channel speichert keine Payloads (Storage-Policy MINIMAL), ein inhaltlicher Vergleich ist deshalb nicht möglich

Das letzte Urteil ist Absicht: Ein Channel, der aus Datenschutzgründen keine Payloads speichert, bekommt kein erfundenes „identisch”, sondern die ehrliche Auskunft, dass hier nichts zu vergleichen ist.

Beim Merge eines Branches schreibt Brio-IO eine Zusammenfassung nach audit/branch-summaries/ in die Konfiguration auf main — inklusive einer begrenzten Zahl konkreter Abweichungs-Beispiele (Standard: 20). Wird ein Branch gelöscht, räumt Brio-IO seine Laufzeit-Routen und seine Datenzeilen ab.

Die heutige Grenze: kein Branch-Deploy

Einen branch-bezogenen Channel deployen kannst du heute nicht. Der Server lehnt das ab:

HTTP 409 Conflict
Branch deployment is not available while branches share the runtime context.
Validate branches via Shadowing; branch deploy becomes available with isolated
contexts.

In der Web-UI ist der Deploy-Schalter im Branch-Kontext deaktiviert und erklärt sich per Tooltip. Das ist kein Fehler. Der Grund ist konkret: Alle Branches teilen heute denselben Laufzeit-Kontext. Ein branch-bezogener Deploy würde deshalb die gemeinsame Route überschreiben — also den Live-Channel verändern, obwohl man glaubt, nur einen Branch zu testen. Lieber eine ehrliche Sperre als eine Funktion, die etwas anderes tut, als ihr Name verspricht.

Der Validierungsweg ist damit: Branch anlegen → Shadowing beobachten → vergleichen → mergen. Der isolierte Kontext je Branch, der den Branch-Deploy freischalten würde, ist in Arbeit.

Was Brio-IO heute nicht tut

Aus demselben Grund, aus dem der Branch-Deploy gesperrt ist, steht hier eine kurze, ehrliche Liste:

  • Kein Channel-zu-Channel-Dispatch im Skript. Ein router.routeMessage() wie in Mirth gibt es nicht; der Weg ist eine Destination am Channel. Der Mirth-Importer warnt genau darauf hin.
  • Kein LIVE-Modus für Branches (paralleler Echtbetrieb zweier Zweige).
  • Kein öffentlicher Download. Brio-IO ist im Early Access; Zugänge werden persönlich eingerichtet.

Diese Seite gibt es bisher auf Deutsch und Englisch. Die spanische Fassung folgt.