Transaktionen
BPM und Transaktionen
Das Arbeiten mit Prozessen, sei es ereignisgesteuert oder mit Benutzerinteraktion, erfordert ein besonders Verständnis für die transaktions-relevanten Abläufe in BPM. Die allgemeine Transaktionsverwaltung obliegt dem Applikationsserver. Wird eine Server-Funktion durch den Client oder von außen durch einen Webservice oder eine zeitgesteuerte Aktion auf dem Applikationsserver aufgerufen, so wird eine neue Datenbank-Transaktion initiiert. Alle Daten, die in dieser Transaktion manipuliert werden, sind für andere Datenbank-Transaktionen erst sichtbar, wenn diese Transaktion abgeschlossen wurde.
Die Transaktion wird erst beendet sobald, die Rückgabe aus der aufgerufenen Server-Funktion erfolgt.
Automatische Transaktionsverwaltung
Ein Prozess läuft daher meist in mehreren Transaktionen ab. Die Transaktionsgrenzen werden durch Wartezustände definiert. Dazu zählen
Benutzeraktionen
Eingehende Nachrichten-Zwischenereignisse
Zeitliches Zwischenereignis
Transaktions-unterbrechendes Zwischenereignis (neu ab 15.2)
Eine Transaktion startet nicht zwingend mit dem Start des Prozesses oder endet mit dem Ende des Prozesses. Da ein Prozess im Kontext von Server-Funktionen aufgerufen werden kann, startet die Transaktion schon mit Beginn der Server-Funktion und endet auch erst mit der Rückgabe aus dieser Funktion. Die Ausführung eines ereignisbasierten Prozesses, wie z.B. beim Speichern eines Datensatzes, findet innerhalb der Transaktion des Speichervorgangs statt.
Anders verhält es sich beim manuellen Start von Prozessen. Dort startet die Transaktion mit dem Start des Prozesses und endet mit dessen Ende oder mit dem ersten prozessunterbrechenden Wartezustand.
Enthält der Prozess mehrere Wartezustände, d.h. Benutzeraktionen oder Zwischenereignisse, so werden die Datenänderungen in aufeinanderfolgenden Transaktionen ausgeführt. Die Dauer des Wartezustandes bestimmt den Zeitpunkt, ab wann eine neue Transaktion durch das Fortsetzen des Prozesses gestartet wird. Je nach Konfiguration oder nach Benutzerinteraktion kann der Wartezustand wenige Sekunden bis mehrere Tage andauern. Wird eine Benutzeraktion geöffnet, so startet dies keine Transaktion. Erst wenn der Benutzer die Aktion abschließt, wird eine neue Transaktion gestartet. Ebenso verhält es sich, wenn der Prozess durch eingehende Nachrichten per Mail oder Webservice weitergeführt wird.
Die Standard-Transaktionszeit wird vom Applikationsserver mit 5 Minuten vorgegeben. D.h. alle serverseitigen Aktionen und die Datenverarbeitung in Skript-Aktionen dürfen zusammen maximal 5 Minuten betragen, da sonst die Transaktion mit allen Datenänderungen zurückgerollt wird. Auch bei Fehlern in der Prozess-Ausführung wird die Transaktion abgebrochen.
Alle in dieser Transaktion durchgeführten Datenänderungen werden zurückgenommen. Änderungen aus vorherigen Transaktionen bleiben bestehen.
Transaktions-Zwischenereignis
Für die Verarbeitung von Massendaten reicht die Transaktionszeit von 5 Minuten nicht aus. Um eine längere Transaktionszeit im Prozess zu definieren, muss die laufende Prozess-Transaktion durch das Transaktions-Zwischenereignis unterbrochen werden. Mit dem Abschluss der laufenden Transaktion wird Serveraufruf beendet und die Kontrolle geht an den Client zurück. Durch das Transaktions-Zwischenereignis wird der Prozess automatisch asynchron im Hintergrund auf dem Applikationsserver weitergeführt.
Das Zwischenereignis erlaubt es eine neue, langandauernde Transaktion zu starten. Die Transaktion läuft maximal für 24 Stunden.
Die nachfolgenden Skriptaktionen, können nun Massendaten innerhalb einer Transaktion verarbeiten. Bei sehr großen Datenmengen ist es ratsam die Verarbeitung auf Datenblöcke aufzuteilen.
Um Massendaten in älteren Version (15.1 etc.) verarbeiten zu können wurde mancherlei Tricks angewandt, die allesamt aber nicht zuverlässig arbeiten. Die Validierung von Prozessen über CURSOR-BPM wurde daher um die Erkennung dieser Workarounds erweitert.
Zeitliches Zwischenereignis ohne Zeitangabe
Der Prozess wird ähnlich wie beim Transaktions-Zwischenereignis unterbrochen und asynchron weitergeführt. Das Problem ist aber, dass das Weiterführen nicht auf das Transaktionsende des unterbrochenen Prozesses wartet.
Die Transaktion vor dem Zwischenereignis ist noch nicht auf der Datenbank persistiert und die neue Transaktion nach dem Zwischenereignis kann auf die neusten Daten nicht zuverlässig zugreifen.
Asynchroner Prozess-Start in Skript-Aktionen
Über ProcessUtils.startProcess()
ist es möglich, einen anderen Prozess asynchron aufzurufen. Dies wird teilweise verwendet, um den eigenen Prozess in einer Schleife immer wieder selbst aufzurufen und Massendaten blockweise abzuarbeiten. Der asynchrone Start wartet zwar im Standard eine Sekunde. Diese Zeit reicht aber nicht immer aus, damit der vorherige Prozess seine Transaktion vollständig abschließen kann. D.h. der neue Prozess kann auf nicht aktualisierte Daten zugreifen.
Daher sollte das Starten von asynchronen Prozessen nur genutzt werden, um andere Aufgaben aus dem Prozess anzustoßen, die nicht auf die Daten des aufrufenden Prozesses zugreifen müssen. Sind Daten aus dem vorherigen Prozess nötig, sollten die Daten als Parameter direkt an den Prozessaufruf übergeben werden. Alternativ sollte der Prozess synchron gestartet werden, wodurch er auf dieselbe Transaktion zugreift.
Sich selbst beendende Benutzeraktion
Um den Transaktionsabschluss zu erzwingen wurde teilweise eine Benutzeraktion verwendet, die sich beim Öffnen direkt beendet. Diese Aktionen sollten durch das neue Transaktions-Zwischenereignis ersetzt werden.
Skript der benutzeraktion
initTask() {
TaskUtils.completeTask();
}
Fehlerbehandlung bei asynchroner Ausführung
Wird ein Prozess asynchron gestartet und läuft bei der Ausführung (ohne Unterbrechung) auf einen Fehler, so wird der Fehlerzustand nur im Log sichtbar, da die aufrufende Stelle auf keine Antwort des Prozesses wartet. Für asynchron gestartete Prozesse muss der Aufruf wiederholt werden.
Bei Asynchronen Zwischenereignissen liegt es an der Definition, ob die Instanz nach einem Fehler nach der Prozessweiterführung nochmals weitergeführt werden kann. Bei einem Mail-Eingang könnte die Mails nochmals importiert werden. Bei Webservices kann der Aufruf ebenfalls mit korrigierten Daten wiederholt werden.
Problematisch ist es beim Zeitlichen- und Transaktionsunterbrechendem- Zwischenereignis. Diese Ereignisse werden serverintern ausgeführt. Daher kann kein Anwender oder Administrator die Prozess-Instanz manuell weiterführen. Die Prozess-Maschine versucht maximal dreimal das Zeitliche-Zwischenereignis fortzuführen. Im transaktionsunterbrechenden Zwischenereignis befindet sich eine Einstellung (Abbruch bei Fehler), worüber im Fehlerfall ein Prozess-Abbruch bewirkt wird. So könnte ein über Timer gesteuerter Prozess nach erfolgtem Abbruch über den Timer erneut gestartet werden.
Zugriff auf Datenänderungen in einer Transaktion
Bis zur Version 15.1 können nicht alle Änderungen auf der Datenbank mittels einer Suche ausgelesen werden, obwohl man sich in derselben Transaktion, z.B. in derselben Skript-Aktion befindet. Betroffen hiervon sind
WorkSpaceScriptUtils.saveEntry
WorkSpaceScriptUtils.deleteEntryAt
WorkSpaceScriptUtils.setRightTemplate
Die Datenänderungen durch diese Methoden wurden nicht direkt zur Datenbank übertragen und sind deshalb auch nicht per SQL-Suche auswertbar gewesen. Im Standard des Applikationsservers werden Datenänderungen in einem eigenen Cache vorgehalten und erst mit Transaktionsabschluss zur Datenbank übertragen. Neuanlagen hingegen werden direkt auf der Datenbank-Transaktion sichtbar und nicht im Cache des Applikationsservers gehalten.
Mit Version 15.2 wurde das Verhalten dieser Methoden angepasst. Mit jedem Aufruf werden alle Änderungen die noch im Cache des Applikationsservers der aktuellen Transaktion stehen zur Datenbank übertragen (Stichwort: Expliziter Flush). Dadurch sind nun auch Datenänderungen direkt per SQL-Suche auswertbar.
Dies erleichtert das Arbeiten mit Datenbankzugriffen in allen Prozess-Skripten.