Asynchrone Programmierung ermöglicht es Ihnen, Aufgaben zu verteilen. Diese Aufgaben können Sie ausführen, ohne den Hauptprozesses/-Thread (z. B. die Navigation und Nutzung der App) zu blockieren. Das Ganze wird oft mit Parallelisierung in Verbindung gebracht, bei der voneinander unabhängige Aufgaben nebenläufig ausgeführt werden. Genau das erreicht die asynchrone Programmierung.

hero-bp-asynchronous-vs-synchronous-programming

Mithilfe von Parallelisierung können Sie Dinge, die normalerweise sequentiell verarbeitet werden, aufbrechen. Das bedeutet, dass Aufgaben in kleinere Teilstücke aufgeteilt werden, die unabhängig voneinander und zeitgleich ausgeführt werden können. Parallelisierung bezieht sich nicht nur auf Prozesse und Funktionen, sondern auch auf die Art und Weise, wie Systeme und Software entworfen werden. Der größte Vorteil der Anwendung von Parallelisierungsprinzipien besteht darin, dass Sie deutlich schneller zum Ziel kommen. Zudem lässt sich Ihr System einfacher weiterentwickeln und wird widerstandsfähiger gegenüber Störungen.

Klingt gut, oder? Dennoch sollten nicht alle Prozesse den Parallelisierungsprinzipien folgen und asynchron ausgeführt werden. In diesem Blogbeitrag erfahren Sie, wann sich die asynchrone Programmierung empfiehlt und wann eine synchrone Ausführung die bessere Option ist.

Asynchrone vs. synchrone Programmierung

Bevor wir zum eigentlichen Thema kommen, wollen wir den Unterschied zwischen asynchroner und synchroner Programmierung klarstellen.

Bei synchronen Vorgängen wird nur eine Aufgabe zur Zeit ausgeführt. Erst wenn eine Aufgabe abgeschlossen ist, wird die nächste entsperrt. Sie müssen also warten, bis eine Aufgabe erledigt ist, um zur nächsten überzugehen.

Bei asynchronen Vorgängen können Sie dagegen zu einer anderen Aufgabe wechseln, bevor die vorherige abgeschlossen ist. So können Sie mehrere Anfragen gleichzeitig bearbeiten und in einem wesentlich kürzeren Zeitraum mehr Aufgaben abarbeiten.  

asynchronous-vs-synchronous-programming-01 

Wann sollte man asynchrone Programmierung anwenden?

Wie bereits erwähnt, ist die asynchrone Ausführung nicht für alle Anwendungsfälle das beste Szenario. Sie sollten sie nur dann nutzen, wenn Sie es mit voneinander unabhängigen Aufgaben zu tun haben. Wenn Sie ein System entwerfen, müssen Sie zunächst die Abhängigkeiten zwischen Prozessen identifizieren und definieren, welche sich unabhängig voneinander ausführen lassen und welche als Folge anderer Prozesse ausgeführt werden müssen.

Schauen Sie sich dazu die Abbildung oben an. Oben sehen Sie, dass die Aufgaben bei einer synchronen Ausführung sequenziell ausgeführt werden. Zuerst kommen die Produkte, dann die Kunden und zum Schluss die Bestellungen.

Angenommen, Sie haben eine Analyse durchgeführt und sind zu dem Schluss gekommen, dass zwischen Kunden und Prozessen keine Abhängigkeit bestehen. Nur für die Ausführung von Bestellungen benötigen Sie zunächst Informationen zu Produkten. Hier gibt es also eine Abhängigkeit. In diesem Fall lassen sich die ersten beiden Aufgaben asynchron ausführen. Bestellungen dagegen werden erst ausgeführt, wenn alle Produkt-Aufgaben abgeschlossen sind. Diese Aufgabe ist also synchron.

Wenn Sie bei unabhängigen Aufgaben parallele und asynchrone Programmierung anwenden, kommen sie deutlich schneller zum Ziel als mit einer synchronen Ausführung. Durch die gleichzeitige Ausführung gibt Ihr System früher wertvolle Ressourcen frei und ist bereit, andere Prozesse in der Warteschlange auszuführen.

Wie Sie ein asynchron laufendes System entwerfen

Um besser zu veranschaulichen, wie Sie ein System entwerfen, das asynchronen Programmierprinzipien folgt, schauen wir uns ein typisches Anspruchsbearbeitungsportal an. Das sieht etwas so aus:

asynchronous-vs-synchronous-programming-02 

Es handelt sich um das Portal, das Versicherungsnehmer oder andere Stellen zur Eingabe und Verwaltung von Anspruchsinformationen nutzen. Dieses Portal kommuniziert über eine API mit einem System zur Validierung von Ansprüchen. Das System importiert Daten in eine Business Validation Engine, die einen Broker und Geschäftsregeln umfasst, die prozess- und logikunabhängig von externen Systemen sind. Zudem ist dieses System mit Zahlungskanälen integriert, in die es die Ergebnisse der Geschäftsvalidierung exportiert. 

Ich zeige Ihnen nun, wie Sie ein System implementieren, das mit der OutSystems-Plattform asynchrone Verarbeitung ausführen kann. Auch wenn Sie kein OutSystems-Entwickler oder -Architekt sind, lohnt es sich weiterzulesen. Sie werden sehen, wie ich parallele asynchrone Prozesse automatisiere, und können das Ganze auf Ihre bevorzugte Technologie übertragen.

Übrigens haben ich vor Kurzem zusammen mit meinem Kollegen Davide Duarte eine Demo erstellt, in der wir alle Schritte zur Automatisierung dieser Prozesse gezeigt haben. Schauen Sie sich unsere Session zum Einsatz asynchroner Techniken an, um mehr zu erfahren.

Da wir OutSystems verwenden, will ich noch kurz auf einige Begriffe und Funktionen eingehen (und dann geht es los, versprochen!). Wenn Sie damit bereits vertraut sind oder einfach nur die vorgeschlagene Architektur sehen möchten, können Sie den folgenden Abschnitt überspringen.

Die asynchronen Funktionen von OutSystems

OutSystems ist eine moderne, KI-gestützte Applikationsplattform, die mehrere integrierte asynchrone Funktionen bietet:

  • Timer: Timer sind für Routineaufgaben wie das Versenden von E-Mails gedacht, die wie ein Digest termininert sind, aber auch für lange und aufwändige Verarbeitungsaufgaben. Wenn Sie Daten für die Nutzung nach der Veröffentlichung einer App vorbereiten möchten, können Sie Timer auch für die Ausführung von Bootstrap-Logik verwenden. Außerdem sind sie empfohlen, um große Informationspakete zu verarbeiten, die einige Zeit zur Ausführung benötigen (20–30 Minuten).
  • Business Process Technology (BPT): Diese Funktion dient dazu, Geschäftsprozesse über mit OutSystems erstellte Apps zu definieren und auszuführen. BPT führt System-zu-System- und Mensch-zu-System-Interaktionen durch. Darüber hinaus unterstützt sie Geschäfts-Workflows und kann mehrere Aktivitäten pro Prozess bearbeiten. Diese Aktivitäten können automatisch oder von Menschen durchgeführt werden.
  • Light Processes: Hierbei handelt es sich um ereignisgesteuerte Prozesse. Stellen Sie sie sich als Trigger vor. Sie sind für die Verarbeitung von mehreren tausend Ereignissen pro Tag gedacht, z. B. als Event-Broker, die eine skalierbare Datenbankwarteschlange benötigen. Im Vergleich zu BPT unterstützen sie nur eine Aktivität innerhalb jedes Prozesses und diese muss eine automatische Aktivität sein.

Darüber hinaus gibt es noch ein paar andere wichtige Funktionen, die Sie kennen sollten:

  • Retry on Error: Wenn ein Fehler auftritt, werden Timer und Prozesse bis zu dreimal wiederholt.
  • Timeout Protection: Der Timeout-Schutz verhindert die unendliche Ausführung eines Hintergrundprozesses und ermöglicht so eine Kontrolle über die Ressourcennutzung.
  • Queue Management: Warteschlangen werden automatisch von der Plattform verwaltet, sodass Sie sich keine Gedanken über das Einreihen von Hintergrundprozessen in die Warteschlange machen müssen.
  • Scalability vs. Parallelization: Prozesse, die im Hintergrund in die Warteschlange gestellt werden, werden vom Frontend automatisch verteilt. Sie brauchen sich also nicht darum zu kümmern.
  • Isolation: Hintergrundprozesse können pro Frontend sowohl für Cloud- als auch für lokale Infrastrukturen oder pro Zone isoliert werden, wenn Sie nur mit lokaler Infrastruktur arbeiten. Dies bietet Ihnen zusätzliche Sicherheit.

Automatisierung paralleler asynchroner Prozesse eines Anspruchsbearbeitungsportals: Architektur-Vorschlag

Schauen wir uns das System zur Validierung von Ansprüchen einmal genauer an:

asynchronous-vs-synchronous-programming-03 

Die API fügt die einzelnen Ansprüche in einen Staging-Datenbereich ein. Anschließend prüft ein Timer, der für einen bestimmten Zeitpunkt angesetzt ist, diese Ansprüche. Beachten Sie, dass jeder Anspruch eine Struktur ist, die mehrere Datensätze enthalten kann. Der Timer validiert und unterteilt also die Ansprüche und Aufzeichnungen und führt ein Bulk Insert (Masseneinfügen) in die Geschäftseinheiten für die Ansprüche durch.

Nun wollen wir unsere Ressourcen so weit wie möglich optimieren. Aus diesem Grund werden wir nicht jeden einzelnen Datensatz verarbeiten, sobald er in die Tabelle eingefügt wird. Zudem wollen wir auch den Overhead des Beginns eines Validierungsprozesses beseitigen. Deshalb nutzen wir eine Bucket Control. Dabei handelt es sich um einen Datensatz, in dem Sie den Anfangsdatensatz und den Enddatensatz angeben. Der Bucket ist also im Grunde ein Intervall von Datensätzen und Ansprüchen, die bearbeitet werden sollen.

Damit lösen wir für jeden Bucket-Datensatz einen Light-Prozess aus, der alle Datensätze im Bucket verarbeitet. Mit „Verarbeitung“ ist im Grunde die Anwendung von Regeln gemeint. Bei den Regeln handelt es sich um „Plug-and-Play“-Engines, d. h. sie können zur Laufzeit zum System hinzugefügt werden.

Sobald ein Datensatz verarbeitet wird, wird er, sofern er gemäß den Geschäftsregeln als gültig gilt, als solcher gekennzeichnet. Ein Timer aggregiert dann die Daten und sendet sie entsprechend an den Kanal.

Dies ist unsere vorgeschlagene Architektur:

asynchronous-vs-synchronous-programming-04 

Zunächst sammelt die Claims API alle Daten, die über eine JSON-Struktur oder XML importiert werden. Alle Daten werden dann in die Staging-Entität eingefügt. Ziel ist es, das Einfügen von Daten zu beschleunigen und Datenverlust zu verhindern.

Sobald die Daten eingefügt sind, startet ein Timer nach einem bestimmten Zeitplan. Der Zweck dieses Timers ist die Unterteilung von Ansprüchen auf der Grundlage der zuvor definierten Claims Rules (Anspruchsregeln) und die Durchführung des Bulk Insert. Auf der Grundlage dieser Regeln werden die Ansprüche in den Claims Service eingefügt.

Die Anzahl der Datensätze in jedem Bulk ist die Anzahl der Datensätze, die Sie innerhalb eines Zeitlimits von drei Minuten verarbeiten können. Zu diesem Zeitpunkt sollten Sie vermeiden, dass noch parallele Kapazitäten zur Verfügung stehen, und nur einen Light-Prozess zur Zeit laufen lassen, da Sie einen Bucket mit einer großen Anzahl von Ansprüchen spezifizieren.

Sobald die Bucket Control erstellt wurde, wird ein Light-Prozess ausgelöst.

asynchronous-vs-synchronous-programming-05 

Dies sorgt dafür, dass der Prozess ausgeführt wird.

asynchronous-vs-synchronous-programming-06 

Die Claims Broker Engine erhält die Regeln, die in den Claims Rules vordefiniert wurden. Basierend auf der Konfiguration werden die Regel-Engine-Endpunkte identifiziert – bei denen es sich im Grunde um REST-APIs handelt, da wir Regel-Engines via Plug-and-Play in unserem System ausführen wollen – und die Ausführung wird in die Warteschlange gestellt.

Sobald wir alle Rule-Engines erhalten, die wir für die Ausführung dieses bestimmten Typs benötigen, und auch die Endpunkte für sie haben, rufen wir sie nun nacheinander auf. Diese Regeln wenden wir nun auf Anspruchsdaten an.

asynchronous-vs-synchronous-programming-07 

Jede Regel führt dazu, dass ein Anspruch entweder als „gültig“ eingestuft wird und somit zum nächsten Schritt übergeht – oder als „nicht gültig“ eingestuft wird und vom System abgelehnt wird.

Schließlich erhält das System einen Timer, der je nach Priorität alle gültigen Ansprüche erfasst, sie aggreggiert und an die Zahlungskanäle weiterleitet.

asynchronous-vs-synchronous-programming-08 

Sie können die Priorisierungsregeln auch komplexer gestalten. So können Sie z. B. festlegen, dass bestimmte Ansprüche so schnell wie möglich gesendet werden sollen. Das bedeutet, dass sie sofort nach der Validierung durch das System versandt werden müssen und zur Zahlung bereit sind. Alternativ können Sie bestimmte Ansprüche auch als Ansprüche mit niedriger Priorität definieren, die durch den Timer bearbeitet werden können.

Ein weiterer Vorteil dieser Art von Schritt-für-Schritt-Regeln in der Engine ist, dass sich das System auch von einer Zeitüberschreitung oder sogar einem Absturz erholen kann. Stellen wir uns vor, dass es nach der Verarbeitung von Regel 1, aber vor der Ausführung von Regel 2 zu einer Zeitüberschreitung oder einem schwerwiegenden Fehler im Prozess kommt und das System wiederhergestellt werden muss. Mit dem vorliegenden System lässt sich jeder der Ansprüche genau an dem Punkt wiederherstellen, an dem er sich vor dem Vorfall befand. In diesem Fall würde der Anspruch also wiederhergestellt werden und Regel 2 ausführen, anstatt Regel 1 zu wiederholen.  

Die wichtigsten Erkenntnisse

Ich hoffe, dass dieser Artikel Ihnen hilft, Ihre Fragen zum Einsatz asynchroner oder synchroner Programmierung zu klären. Hier sind noch einmal die wichtigsten Punkte im Überblick:

  • Verwenden Sie die asynchronen Techniken, die für das Ergebnis besser geeignet sind.
  • Skalieren Sie Frontend-Server und Konfigurationen so, dass sie Ihren Anforderungen entsprechen. Denken Sie daran, dass Sie bei Millionen Datensätzen mehr Frontend-Server benötigen, um Ihre Anforderungen zu erfüllen. 
  • Entwerfen Sie mit Blick auf Flexibilität und vermeiden Sie fest kodierte Werte oder Site-Eigenschaften. Angenommen, Sie verwenden fest kodierte Werte für die Bucket-Kontrolle. Wenn Ihr Validierungsprozess langsamer wird und Sie dies aus irgendeinem Grund nicht bemerken, kommt es zu Timeouts. Jetzt sind Sie in einer noch ungünstigeren Situation – denn Sie müssen die Änderungen veröffentlichen und können nicht in ein Backoffice gehen, um sie zu ändern.
  • Übertreiben Sie Ihr Engineering nicht. Versuchen Sie, Ihre Architektur und Ihr System so einfach wie möglich zu halten.  

Das vorgestellte Szenario können Sie auch in meinem letzten TechTalk in Aktion sehen: How to Use Asynchronous Techniques in OutSystems. Mein Kollege Davide und ich zeigen Ihnen die beschriebene Lösung und nutzen dabei die asynchronen Funktionen von OutSystems, die Skalierbarkeit und Ausfallsicherheit fördern und große Datenmengen verarbeiten können.