Publish-Subscribe mit System Events

Publish-Subscribe, kurz Pub/Sub, ist ein Messaging Pattern das einem erlaubt, den Sender (Publisher) einer Nachricht von den Empfängern (Subscriber) zu entkoppeln. D.h. der Publisher sendet eine Nachricht, wie z.B. Dokument generiert, an eine Zentrale Stelle, auch Broker genannt. Der Broker sendet diese Nachricht nun an alle Subscribers, die sich für diese Nachricht interessieren.

Abb. 1: Pub/Sub


Diese Funktion wird meistens von so genannten Message-Oriented-Middlewares, kurz MOM, bereit gestellt und von APIs wie z.B. JMS implementiert.

Doch was ist der Nutzen von Pub/Sub? Das lässt sich anhand eines Beispieles am besten zeigen.

Nehmen wir an, wir haben einen Prozess der am Ende ein Dokument generiert und dieses Dokument per Email versendet. Nachdem der Prozess eingeführt wurde, will der Kunde, dass dieses Dokument zusätzlich archiviert wird. Gesagt, getan.

Der Prozess ist ein voller Erfolg und wird an einen weiteren Kunden verkauft. Dieser will aber, dass das Dokument weder per Email versendet noch archiviert wird, sondern per FTP hochgeladen wird.

Wie kann dies nun gelöst werden? Eine beliebte Möglichkeit ist das erstellen eines CallSub der per Kunden Projekt und Override überschrieben wird. Dies bedingt jedoch, dass der Prozess aus dem Kundenprojekt gestartet wird und je nach Situation werden Funktionalitäten dadurch dupliziert.

Eine andere Möglichkeit ist Pub/Sub mit System Events. Der Prozess (Publisher) ruft nun nicht mehr den CallSub auf, sondern sendet einen System Event Dokument generiert. Subscribers in Form von Event Start Beans empfangen nun dieses System Event.

Der Vorteil einer solchen Nachrichten basierten Architektur ist, dass man nun Teile der Applikation einfach hinzufügen und wieder wegnehmen kann, ohne das andere Teile der Applikation betroffen sind.

In unserem Beispiel könnten wir die einzelnen Funktionen (Email senden, archivieren, FTP etc.) in Projekte ablegen und je nach bedarf deployen. Diese würden dann das System Event empfangen und ihre Aufgabe unabhängig von einander verrichten.

System Events

Xpert.ivy bietet zwar keine MOM, doch mit den System Events bietet sich eine Möglichkeit, Pub/Sub ohne weitere Bibliotheken zu implementieren.

Xpert.ivy hat 2 Kategorien von System Events. Workflow und 3rd Party.

Workflow System Events werden von Xpert.ivy generiert und man kann selber keine generieren. Es gibt 4 Events die man empfangen kann:
  • WorkflowSystemEvent.TASK_CREATED
  • WorkflowSystemEvent.TASK_CHANGED
  • WorkflowSystemEvent.CASE_CREATED
  • WorkflowSystemEvent.CASE_CHANGED
3rd Party System Events können Sie dagegen selber generieren und empfangen.

Beispiel Projekt

Unter http://xpert-ivy-hacker-source-code.googlecode.com/svn/trunk/PublishSubscribe habe ich Ihnen ein Beispiel Projekt zur Verfügung gestellt.

System Events senden

In Ivy gibt es 2 Möglichkeiten System Event zu senden. 1 davon funktioniert nur in User Dialogen. Die andere, die ich Ihnen zeigen werden, funktioniert in Prozessen wie auch in User Dialogen. Wenn Sie wissen wollen, wie Sie mit einem User Dialog Interface System Events empfangen und senden können, öffnen Sie die Hilfe und suchen Sie nach System Event.

Im Code Snippet 1 ist zu sehen, wie man 3rd Party System Events versendet.

Code Snippet 1: System Event senden

Auf Zeile 5 wird das System Event erstellt. Der erste Parameter ist die Kategorie und muss immer THIRD_PARTY sein. Der zweite Parameter ist der Name des System Events. Auf diesen Namen müssen die Subscribers hören, wenn sie diesen Event empfangen wollen. Der letzte Parameter ist der Payload den man dem System Event mitgeben kann und ist optional.

System Events empfangen

Um System Events empfangen zu können, muss ein ISystemEventListener registriert werden. Ich habe dazu ein Event Start Bean (SystemEventSubscriber.java) geschrieben, dass dazu verwendet werden kann. Im folgenden Code Snippet sieht man die relevanten Teile, um einen ISystemEventListener zu erstellen und zu registrieren.

Code Snippet 2: ISystemEventListener erstellen

Ein ISystemEventListener registriert sich nicht auf einen bestimmten Event, sondern empfängt alle die gesendet werden. Es ist die Aufgabe des Listeners nur die Events zu verarbeiten, an denen er interessiert ist. Auf Zeile 4 sieht man, wie der Listener die Events herausfiltert.

Damit der Listener Events empfängt, muss, wie auf Zeile 15 zu sehen ist, der Listener registriert werden.

Wenn der Listener nicht mehr benötigt wird, muss dieser unbedingt wieder entfernt werden. Dies ist z.B. der Fall, wenn das Event Start Bean gestoppt wird.

Code Snippet 3: Listener entfernen

Wenn dies nicht gemacht wird kann es sein, dass unerwünschte Effekte auftreten, wie z.B. das Events in alten Prozess Model Versionen verarbeitet werden.

Limitationen und Tücken von System Events

Während System Events auf den ersten Blick nach einem tollen Ersatz für MOMs aussehen, muss man sich ihrer Limitationen und Tücken bewusst sein.

Die grösste Limitation von System Events ist das Fakt, dass es keine Garantie gibt das die Nachrichten auch ankommen. Während dies bei MOMs realisiert werden kann, bieten System Events keine solche Funktion an. Hier ein Beispiel, wie eine Nachricht verloren gehen kann.

Nehmen wir an, wir haben ein Projekt A das System Events versendet. Projekt B empfängt diese. Nun wollen wir Projekt B updaten. D.h. wird deaktivieren Projekt B. Wenn nun während dieser Zeit eine Nachricht von Projekt A gesendet wird, so wird Projekt B nach dem aktivieren diese Nachricht nicht sehen. Die Nachricht geht verloren.

Um dies zu verhindern könnte z.B. die Applikation deaktiviert werden.  Man muss jedoch immer noch aufpassen, dass Projekt A nicht vor Projekt B aktiviert wird und schon Nachrichten sendet bevor Projekt B aktiviert ist. Sonst gehen diese Nachrichten verloren.

Ein weiteres Problem ist das senden von Objekten als Parameter und unterschiedliche Prozess Model Versionen (PMVs).

Als Beispiel nehmen wir die beiden Projekte A und B vom vorherigen Beispiel. Projekt B ist abhängig von A.

Projekt A (A1) erstellt Tasks, die nachdem aufnehmen einen System Event mit einem Parameter von einer Datenklasse in Projekt A versenden. Nun erstellen wir eine neue PMV von Projekt A (A2).

Wenn nun in A1 ein Task aufgenommen wird und somit ein System Event mit der Datenklasse als Parameter versendet wird, so wird es in Projekt B zu einer "merkwürdigen" Exception kommen.

Can not cast object projektA.MeineDatenklasse to projektA.MeineDatenklasse.

Der Grund dafür ist, dass MeineDatenklasse die von A1 gesendet wird und MeineDatenklasse die von Projekt B verwendet wird von 2 unterschiedlichen Classloaders kommen. Nämlich vom Projekt Classloader A1 und vom Projekt Classloader A2. Da Projekt B nun A2 verwendet, kann es die Datenklasse von A1 nicht casten, auch wenn sich nichts an der Datenklasse geändert hat.

Eine Lösung um dieses Problem zu vermeiden ist, den Parameter im Projekt A z.B. in einen JSON String zu Serialisieren und in Projekt B wieder in ein Objekt zu Deserialisieren.

Eine weitere Möglichkeit ist nur mit IDs als Parameter zu arbeiten. Die Subscribers können bei Bedarf das Objekt per ID laden.

Message oriented architecture mit Xpert.ivy & JMS Extension

Will man weitergehen als Pub/Sub, stösst man mit System Events schnell auf Grenzen. Im Ausblick für 2013 habe ich angekündigt, dass ich dieses Jahr Extensions für Xpert.ivy veröffentliche werde. Die erste Extension die ich veröffentlichen werde ist eine JMS Extension. Lesen Sie hier mehr darüber.

Fazit

Pub/Sub mit System Events ermöglicht es losgekoppelte Prozesse zu entwickeln und ist eine einfache alternative zu MOMs, wenn man sich den Limitationen bewusst ist und weiss wie mit ihnen umzugehen ist.
Über den Author: Heinrich Spreiter ist der Gründer von xpertivyhacker.ch. Kontaktieren Sie ihn auf Xing und Twitter

Melden Sie sich für den Xpert.ivy hacker Newsletter an und Sie erhalten immer die neusten Tutorials und Tricks zu Xpert.ivy sobald sie publiziert werden.

Ihre Email Adresse wird nur für diesen Newsletter verwendet und nicht an dritte weitergegeben.

Keine Kommentare:

Kommentar posten

Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.