Service Bus
Schauen wir nun auf die Unterstützung der synchronen und asynchronen Kommunikation durch die Schleupen.CS Plattform an. Zentraler Baustein ist hier der ServiceBus, den wir im Folgenden vorstellen.
Schleupen.CS ServiceBus
Schleupen.CS verwendet einen leistungsfähigen und leichtgewichtigen ServiceBus als Integrationsplattform (siehe auch: CS in a Nutshell). Dieser ermöglicht die schnelle und einfache Nutzung der auf der Plattform verfügbaren Services. Er unterstützt sowohl die synchrone als auch die asynchrone Kommunikation.
Die aktuelle Implementierung von Schleupen.CS verwendet Webservice-Fassaden auf Basis von WCF/ SOAP. Die speziell für die Kommunikation mit anderen Systemen konzipierten privilegierten Schnittstellen, nutzen hingegen REST/Web API. Perspektivisch planen wir REST/Web API-Fassaden für alle Webservices anzubieten.
Synchrone Serviceaufrufe
Der synchrone Aufruf eines Services auf der Schleupen.CS Plattform erfolgt nicht direkt vom Nutzer zum Anbieter, sondern über einen Baustein des ServiceBus, den Service Broker (s.u).
Der Aufruf erfolgt in drei Schritten:
- Der Service Client ruft den Broker-Endpunkt mit einer ServiceId (s.u.) auf.
- Der Broker ermittelt den aufzurufenden Endpunkt des Ziel-Service unter Zuhilfenahme der Service Registry (s.u.).
- Der Broker routet den Aufruf zum ermittelten Endpunkt des Ziel-Service weiter und liefert das Ergebnis zurück an den Service Client.
Schleupen.CS verwendet aktuell für die synchrone Kommunikation das Protokoll HTTP/HTTPS. Zu beachten ist, dass der Client-Code erst nach einer HTTP-Antwort weiterläuft. Dies gilt auch dann, wenn intern Client- oder Serverseitig mit async/await implementiert wurde.
Service Broker
Der Broker stellt eine einheitliche Schnittstelle zur synchronen Kommunikation mit verschiedenen Ziel-Services zur Verfügung. Der Broker steht auf allen Frontend- und Backend-Servern zur Verfügung. Aufgerufen wird meist die lokale Installation (localhost) des Brokers, wobei andere Hosts auch möglich sind.
Der Broker stellt auch Funktionalität zur Beauskunftung von Services zur Verfügung.
WSDL eines Services über den Broker ermitteln
Um einen Service aufzurufen, benötigt man eine möglichst genaue Beschreibung seiner Schnittstelle. Die WSDL ist eine Sprache, in der solche Beschreibungen erstellt werden können. Kennt man die ServiceId - also eine genormte Id zur Identifikation eines Services - so kann man die WSDL-Beschreibung des aufzurufenden Service über den folgenden Broker-Aufruf ermitteln, ohne einen konkreten Endpunkt kennen zu müssen:
https://<host>/Schleupen/Service Bus/Broker/MetadataActivityService.svc/<ServiceId>
https://localhost/Schleupen/Service Bus/Broker/MetadataActivityService.svc/
Schleupen.CS.MT.BIB.Benutzerkonten.BuecherAusleihenActivityService_3.2
Aufruf des Ziel-Service über den Broker
Der Broker-Endpunkt, über den der Zielservice aufgerufen wird, kann auf einem <host> über folgende URL erreicht werden. Die ServiceId wird als Soap Action im HTTP Header angegeben:
https://<host>/Schleupen/Service Bus/Broker/BrokerService.svc + SOAP-Action <ServiceId>
http://localhost/Schleupen/ServiceBus/Broker/BrokerService.svc + SOAP-Action urn://Schleupen.CS.MT.BIB.Benutzerkonten.BuecherAusleihenActivityService_3.2/LeiheAus
Als Ergebnis wir das Ergebnis des Aufrufs des Zielservice zurückgeliefert.
Was passiert im Broker bei einem Service Aufruf?
Zunächst muss der Broker den aufzurufenden Endpunkt des Ziel-Service ermitteln. Hierzu übergibt er die ServiceId an einen weiteren Baustein des Service Bus, die Service Registry.
Diese Implementierung entspricht dem Muster Server-side Service Discovery
Bevor der Broker diesen Endpunkt aufrufen kann, muss der für das aktuelle Systemstrukturlement korrekte Datenkontext bestimmt und im Session Token hinterlegt werden. Als Entwickler des Services oder des Aufrufers muss man sich nicht um dieses Detail kümmern. D.h. es ist möglich, Services und Clients zu entwickeln, die auf verschiedenen Systemen mit unterschiedlichen Systemstrukturen funktionieren.
Was aber, wenn man die ServiceId nicht kennt? Welche Services gibt es überhaupt?
Service Registry
Aktuell sind ca. 5100 Services und 1500 Business Events auf der Schleupen.CS Plattform registriert (Stand: Mai 2024). Es bedarf eines zentralen Verzeichnisses, einer Art "Adressenverwaltung für Services". Die zum Service Bus gehörende Service Registry stellt diese Funktion bereit. Sie bietet folgende Dienste an:
Folgende wesentliche Aufgabenstellungen sind zu bewältigen:
- Auffinden des aufrufbaren Endpunktes für einen Service.
Liefern der URL des Endpunktes. - Auffinden eines Services, dessen ServiceId nicht bekannt ist.
Suche nach einem Service für eine bestimmte Aufgabe.
Liefern der ServiceId. - Abrufen der Schnittstellenbeschreibung eines Services.
Ermitteln der WSDL. - Verwalten der Services.
Registrieren, ändern und deregistrieren von Services.
ServiceId: Eindeutige Identifikation eines Services
Die Service Registry verwendet zur eindeutigen Identifikation eines Services die ServiceId und stellt sicher, dass es diese auf dem System nur einmal gibt. Die ServiceId ist nach folgendem Schema aufgebaut:
<Hersteller>.<Produktkürzel>.<fachlicher Namensraum>.<Servicename>_<Versionsnummer>
Dabei ist
- <Hersteller> derjenige der die Service-Schnittstelle definiert (z.B. Schleupen)
- <Produktkürzel> das Kürzel des Produkts, das die Schnittstelle ausliefert (z.B. CS)
- <fachlicher Namensraum> ein fachlicher Namensraum zur Strukturierung der Services
- <Servicename> soll den hier beschriebenen Regeln genügen
- <Versionsnummer> soll den hier beschriebenen Aufbau haben
Beispiel: Schleupen.AS.MT.BIB.Benutzerkonten.BuecherAusleihenActivityService_3.2 - dabei ist "Schleupen": der Name des Herstellers. Darf keinen Punkt enthalten.
"AS": das von Schleupen verwendete Produktkürzel für CS Architekturbeispiele. Darf keinen "." enthalten.
"MT.BIB.Benutzerkonten": der fachliche Namensraum.
"BuecherAusleihenActivityService": der Servicename (inkl. Service-Kategorie; ohne Punkte)
"3.2": die Versionsnummer.
Die erste Stelle (hier die 3) ist die Architekturversion und die zweite Stelle Versionsnummer entspricht dem MAJOR des Semantic Versioning. MINOR und PATCH sind in den Dokumenten - hier der WSDL - selber hinterlegt, sodass dieser Spezifikation gefolgt wird: Über den Vergleich der Versionsnummer wird die Kompatibilität zweier Services erkennbar. Unterscheiden sich die Versionsnummern in der ServiceId, sind diese inkompatibel. Werden inkompatible Versionen eines Services auf einem System gehostet, haben diese unterschiedliche Endpunkte. Inkompatible Versionen eines Service sind in der Regel nicht ohne Anpassung des Clients aufrufbar. Siehe Kompatibilität von Services.
Beispiel: Ein Service Client ruft die Schnittstelle Schleupen.AS.MT.BIB.Benutzerkonten.BuecherAusleihenActivityService_3.2 auf. Dieser kann nicht ohne Anpassungen den als inkompatibel gekennzeichneten Service Schleupen.AS.MT.BIB.Benutzerkonten.BuecherAusleihenActivityService_3.3 aufrufen.
Die ServiceId ist eindeutig für den Service, nicht für dessen Endpunkte.
In einem System existieren häufig mehrere Endpunkte für einen Service (eine ServiceId) auf verschiedenen Hosts.
Die Auswahl des konkret aufgerufenen Endpunktes des Zielservice ist für den Aufrufer transparent. Die Regeln für die Auswahl sind ein Implementierungsdetail der Plattform und bewusst vor dem Aufrufer verborgen. Dieser Mechanismus kann Funktionen zur Erhöhung der Ausfallsicherheit und Lastverteilung enthalten. Aufrufer können nicht davon ausgehen, dass der Aufruf auf derselben Maschine erfolgt. Dies gilt auch für Entwickler, die einen Service implementieren.
Auffinden eines Service
Über ein Powershell-Skript kann direkt auf die Service Registry des Systems zugegriffen werden (siehe cmdLet Kategorie "Service Bus & Messaging" ). Der WebModeler ermöglicht über die Auswahl "Webservices" den integrierten Zugriff. Alle auf dem System registrierten Services können beauskunftet werden. Eine Alternative für die Schleupen.CS Services ist die Nutzung des Schleupen.CS Service Interface Repository.
Schleupen.CS Service Interface Repository
Wir stellen Exporte der Daten der Service Registry für Kunden, Partner und Mitarbeiter der Schleupen SE bereit. Diese können unabhängig von einem lauffähigen CS-System genutzt werden. Diese Exporte enthalten die uns bekannten Standard-Service einer definierten Hauptversion, jedoch keine individuellen Anpassungen oder Erweiterungen von Partnern.
Integration: Service Interface Repository
Endpunktverwaltung
Endpunkte externer Anbieter wie die von RabbitMQ werden häufig nicht speziell für die Verwendung mit der Schleupen.CS Plattform entwickelt. Konzepte wie die Systemstruktur und das SessionToken sind ihnen unbekannt. Dennoch ist es wichtig, auch solche Services in die Plattform einzubinden. Diese Services werden nicht in der Service Registry, sondern in der Endpunktverwaltung registriert und können ohne Broker, direkt aufegrufen werden. Hierzu gehören auch Services, die von Schleupen entwickelt wurden, um z.B. spezielle Infrastruktur-Aufgaben zu erfüllen oder mit der Vorgängerversion Schleupen.CS 2.0 zu interagieren.
Zur Verwaltung stehen Powershell-Cmdlets zur Verfügung (Add-Endpoint, Select-Endpoint und Remove-Endpoint). Alternativ kann der REST-Service MangeEndpointActivityService verwendet werden.
Der Service ResolveEndpointActivityService kann genutzt werden, um den aufzurufenden Endpunkt zu ermitteln. Auch ein Redirect wird über den Service EndpointRedirectService unterstützt.
Asynchrone Kommunikation - Messaging
Asynchrone Kommunikation kommt an vielen Stellen in Schleupen.CS zum Einsatz. Die wichtigste Form ist das Messaging. Der Sender der Nachricht (= Producer) und der Empfänger (= Consumer) sind zeitlich entkoppelt.
Beim Messaging sendet der Producer eine Nachricht, ohne auf eine unmittelbare Antwort des Consumers zu warten. Der Producer ruft nicht direkt die Consumer auf, sondern gibt die Nachricht bei einer vermittelnde Komponente ab, dem MessageBus.
Für das Messaging wird das asynchrone Protokoll AMQP verwendet.
Vergleich: Im UI-Kontext wird asynchrone Kommunikation über WebSockets eingesetzt, um Inhalte vom Server zu den UI-Clients pushen zu können. Hierzu verwendet Schleupen.CS SignalR. Dies vermeidet ein aufwändiges client-seitiges Polling. Dieser Mechanismus ist in die Schleupen.CS APIs und Services eingebunden und für Entwickler transparent.
MessageBus
Der MessageBus ist der Baustein des Service Bus, welcher die asynchrone Interprozesskommunikation mit Hilfe von Nachrichten ermöglicht. Dabei wird der Producer, d.h. der Programmteil, der die Nachricht erzeugt und an den MessageBus übergibt, nicht blockiert. Der Consumer, d.h. der Empfänger der Nachricht, erhält diese zu einem späteren Zeitpunkt. Es gibt keine Garantie, wann genau die Zustellung der Nachricht erfolgt, wohl aber, dass die Nachricht zugestellt wird.
Im Falle von Störungen kann es vorkommen, dass Nachrichten mehr als einmal zugestellt werden (siehe at least once delivery). Consumer (und in Schleupen.CS Services) müssen aus diesem Grund idempotent implementiert werden. Schleupen.CS stellt C# Entwicklern hierfür eine Idempotenz-Bibliothek zur Verfügung.
Nachrichtenfluss: von Producer zu Consumer
Im folgenden schauen wir uns an, wie eine Nachricht von einem Producer zu dem oder den Consumern gelangt.
Abgabe von Nachrichten beim MessageBus
Nachrichten können über einen Endpunkt des MessageBus abgegeben werden. Dies geschieht analog zum synchronen Service Aufruf, jedoch nicht über den Broker, sondern über den MessageBus:
https://Schleupen/Service Bus/MessageBus/BusinessEvents/BusinessEventPublishingService.svc
Die nachfolgende Abbildung stellt dar, wie ein konkreter Endpunkt für das Auslösen des Business Events BuecherAusgeliehen aussieht:
Dieser Service liefert einen Response, der keinen Payload hat und lediglich signalisiert, ob die Nachricht erfolgreich an den MessageBus übergeben worden ist oder nicht. Dies bedeutet nicht, dass die Nachricht zu diesem Zeitpunkt bereits bei dem oder den Consumern angekommen ist.
Intern wird i.A. mithilfe der Schleupen-Bibliothek Transactional Outbox direkt das Business Event an den MessageBus übergeben.
Das Nachrichtenformat ist identisch zu den Parametern der Schnittstelle bei einem synchronen Aufruf. Die oben beschriebenen Mechanismen, um eine Servicebeschreibung zu finden und einen Service zu nutzen können auch für Business Events genutzt werden.
Um die zeitliche Entkopplung zu ermöglichen, werden die Nachrichten vom MessageBus in einer Message-Queue, einer FIFO-Warteschlage zwischengespeichert. Anschließend kann die Nachricht von einem oder mehreren Consumer(n) empfangen werden.
Empfangen von Nachrichten
Schleupen.CS unterstützt zwei verschiedene Arten für den Empfang von Nachrichten:
- Zustellung an Subscriber
- Abholung durch Competeting Consumer
Business Event Dispatcher - Zustellung an Subscriber
Der Business Event Dispatcher ist die Schleupen.CS Implementierung eines Message Dispatchers und eines Service Activators. Er ließt Nachrichten aus dem MessageBus und stellt diese aktiv an den oder die passiven Empfänger zu. Subrcriber werden als synchrone Services implementiert. Der Business Event Dispatcher ist ein Baustein des Schleupen.CS ServiceBus.
Im Zentrum steht die Schnittstelle des Business Events (hier IBuecherAusgeliehenEvent). Diese wird wie eine synchrone Schnittstelle modelliert und als WSDL veröffentlicht. Der Publisher (linkes Land, blau) verhält sich wie der Aufrufer des Service, der Subscriber (rechtes Land, rot) wie der Anbieter.
Alle im ServiceBus registrierten Implementierungen der Event-Schnittstelle werden als Subscriber angesehen und durch den MessageBus aufgerufen. Die Implementierung einer Event-Schnittstelle erfolgt per WCF.
Die hier dargestellte Zustellung von Business Events erfolgt für Command Messages technisch gesehen analog. Im Unterschied zu Business Events werden die Nachrichten allerdings nur an einen Empfänger zugestellt. Request/Reply ist die zielgerichtete Zustellung mit Antwort und ist aus technischer Sicht die zweifache Nutzung von Command Messages für Hin- und Rückrichtung. Daher ist Request/Reply ein asynchrones Kommunikationsmuster.