Die folgenden Abschnitte zeigen an Hand typischer Anwendungsfälle, wie Sie Service-gesteuerte Queues einsetzen können und wie Sie die zugehörigen Teilprogramme erstellen müssen.
Beispiel 1: Kommunikation zweier Vorgänge in einer Anwendung
Das Bild veranschaulicht die Auswertung eines Hintergrundauftrages mit Hilfe einer Temporären Queue. Der Hauptvorgang "Kunde" in einem Call Center lässt die gewünschten Daten durch einen Hintergrundauftrag suchen und liest die Ergebnisse aus einer Temporären Queue bzw. wartet auf die entsprechende Nachricht, wenn sie zum Zeitpunkt des DGET noch nicht vorliegt.
UTM-Anwendung "Call Center"
Bild: Kommunikation zweier unabhängiger Vorgänge mit Hilfe einer Temporären Queue
Mit QCRE NN wird eine Temporäre Queue erzeugt. Der Name der Queue wird in KCRQN zurückgegeben. Anschließend wird mit FPUT der Hintergrundauftrag "Suchen" erzeugt und die Transaktion sofort mit PEND SP beendet. Beim FPUT wird der Name der Queue im Nachrichtenbereich mitgegeben.
Der Vorgang "Suchen" liest die Nachricht mit dem Namen der Temporären Queue und sucht die gewünschten Daten. In der Zwischenzeit fragt der Hauptvorgang "Kunde" das Ergebnis der Hintergrundverarbeitung mit DGET ab. Da das Ergebnis in diesem Fall noch nicht vorliegt, beendet sich das aktuelle Teilprogramm des Hauptvorgangs; openUTM wartet auf das Eintreffen der Nachricht. Die Funktion ist so realisiert, dass in der Wartezeit für den Hauptvorgang kein Teilprogramm aktiv und kein Prozess gebunden ist.
Wenn der Hilfsvorgang "Suchen" die gewünschten Daten ermittelt hat, dann erzeugt er eine Nachricht für die Temporäre Queue und beendet sich, der DPUT-Auftrag wird damit ausgeführt.
Durch das Eintreffen der Nachricht wird der Hauptvorgang fortgesetzt. Dieser liest das Ergebnis aus der Temporären Queue und schickt es an den Client. Anschließend löscht er die Temporäre Queue und beendet sich (die Löschung wird erst beim erfolgreichen Transaktionsende wirksam).
Zur Steuerung der Abläufe in den Teilprogrammen muss ein Hilfsfeld WaitForMsg
im Kommunikationsbereich KB angelegt werden, damit es von allen Teilprogrammen des Vorgangs zugreifbar ist. Kommt es wiederholt zum Returncode 08Z, so wird das überflüssige Warten durch einen RSET-Aufruf umgangen.
... QCRE NN FPUT mit KCRN=Suchen kb.WaitForMsg = 0 PEND SP mit TAC2
... DGET queue if ( KCRCCC = "08Z" ) then if kb.WaitForMsg = 0 then kb.WaitForMsg = 1 PEND PA,<tac2> else RSET else verarbeitung QREL queue ... PEND FI
Beispiel 2: "Pseudo -Dialoge" mit fernen Transportsystem-Anwendungen
Mit einer einfachen Modifikation von Beispiel 1 ergibt sich ein anderer Anwendungsfall: Ein Dialog- oder Asynchron-Vorgang möchte lesend auf eine Datenbank in einer anderen Anwendung zugreifen.
An die Stelle des Hilfsvorgangs in Beispiel 1 tritt ein Kommunikationspartner vom Typ APPLI oder SOCKET-USP. Dazu adressiert der FPUT-Aufruf im Hauptvorgang an Stelle eines Asynchron-TACs den LTERM-Namen der fernen Anwendung; von dieser Änderung abgesehen bleiben die Aufrufe und Abläufe in den beiden Vorgängen unverändert. Handelt es sich bei der fernen Anwendung um eine UTM-Anwendung, dann muss der TAC, der in der fernen Anwendung aufgerufen werden soll, am Anfang der FPUT-Nachricht stehen. Die ferne Anwendung muss ihre Antwortnachricht mit dem Namen der Queue beginnen, in der der Hauptvorgang die Antwort erwartet.
openUTM bestimmt das Ziel der Nachricht allein aus dem Namen der Queue. Daher darf der Name der Temporären Queue nicht mit einem TAC- oder LTERM-Namen der lokalen Anwendung übereinstimmen. Diese Namenskollision wird dadurch vermieden, dass der Name der Temporären Queue von openUTM vergeben wird (QCRE NN) und weder TAC- noch LTERM-Namen mit einer Ziffer beginnen.
Beispiel 3: Kommunikation mit mehr als einem Vorgang
Möchte ein Vorgang mit mehr als einem Hilfsvorgang gleichzeitig kommunizieren, dann ist der Ablauf ähnlich wie bei der Kommunikation mit nur einem Hilfsvorgang. Beim Lesen der Antworten muss jedoch darauf geachtet werden, dass alle Antworten gelesen werden; dazu muss möglicherweise mehrfach gewartet werden. Dabei müssen Sie darauf achten, dass auf jede Nachricht höchstens einmal gewartet wird.
Zur Steuerung der Abläufe in den Teilprogrammen werden in diesem Beispiel Hilfsfelder im KB angelegt, damit alle Teilprogramme des Vorgangs auf sie zugreifen können. Da es sein kann, dass nicht alle Antworten in einem Teilprogrammlauf gelesen werden können, wird mit Hilfe der Browse-Funktion eine Warteschleife realisiert. Die Antworten werden erst dann verarbeitet, nachdem die letzte Nachricht eingetroffen ist.
Bild: Kommunikation eines Hauptvorgangs mit zwei Hilfs-Vorgängen über Temporäre Queues
Für diese Kommunikation müssen Hilfsfelder verwendet sowie Schleifen programmiert werden. Die einzelnen Schritte werden nachfolgend in Tabellenform erläutert:
Programm TAC1 | Erläuterung |
---|---|
INIT | |
QCRE NN | Temporäre Queue erzeugen. Der Name der Queue wird in KCRQN zurückgegeben. |
FPUT KCRN=HTAC1 | Nachrichten für die Hilfs-Vorgänge erzeugen. Der Name der Queue wird in der Nachricht mitgegeben. |
kb.NrMsgs = 2 | Felder im KB-Programmbereich initialisieren. Diese Felder steuern den Ablauf in den Folgeprogrammen. |
PEND SP KCRN=TAC2 | Transaktion beenden, die Asynchron-Aufträge werden gestartet. |
Programm TAC2 | Erläuterung |
INIT | |
Timeout=0 | Timout-Feld initialisieren. |
for ( kb.i<kb.NrMsgs AND Timeout=0 ) DGET BF mit Länge 0 kb.kcgtm | In einer Schleife wird versucht, mit Hilfe von DGET BF mit Warten alle Antworten abzuwarten, ohne die Daten zu lesen oder zu löschen, d.h. alle Nachrichten bleiben erhalten. |
if ( KCRCCC="08Z" ) then Timeout=1 PEND PA KCRN=TAC2 else kb.i=kb.i +1 kb.WaitForMsg=0 | Muss gewartet werden, dann wird der Programmlauf mit PEND PA beendet; als Folge-TAC wird der aktuelle TAC angegeben. Ist eine Antwort eingetroffen, wird der Zähler erhöht. Die Erzeugungszeit und die DPUT-ID der Nachricht werden zwischengespeichert. |
if Timeout=0 DGET FT DGET NT Verarbeitung | In zwei geschachtelten Schleifen werden alle Antworten vollständig gelesen, dann startet die Verarbeitung der Antworten. Das Ergebnis wird mit MPUT an den Client gesendet. |
else RSET MPUT | Bei Timeout wird das überflüssige Warten durch einen RSET umgangen. |
QREL "Queue" | Vor Beenden des Vorgangs wird die Temporäre Queue wieder gelöscht. |
Beispiel 4: Senden von asynchronen Nachrichten an UPIC-Clients
Asynchron-Nachrichten dürfen nicht an einen LTERM-Partner eines UPIC-Clients gerichtet sein; mit Hilfe von zwischengeschalteten Service-gesteuerten Queues können jedoch auch einem UPIC-Client asynchrone Ereignisse oder Meldungen zugestellt werden. Dazu richtet man die asynchronen Nachrichten entweder an die USER-Queue des UPIC-Clients oder man generiert für jeden UPIC-Client zusätzlich eine TAC-Queue. Der UPIC-Client startet nun parallel zu seinen normalen Dialog-Vorgängen einen weiteren Dialog-Vorgang, der nur die Aufgabe übernimmt, an dieser Queue zu warten bis eine Nachricht eintrifft, diese auszulesen und an den UPIC-Client weiterzuleiten.
Das folgende Diagramm zeigt die Realisierung mit Hilfe von USER-Queues:
Bild: Senden asynchroner Nachrichten an UPIC-Clients mit Hilfe von USER-Queues
Beispiel 5: Serialisierung von Teilprogrammen
Soll ein Programm(abschnitt) serialisiert werden, der sowohl in Dialog- als auch in Asynchron-Vorgängen abläuft, so kann man eine TAC-Queue zur Serialisierung verwenden. TAC-Queues haben gegenüber GSSBs den Vorteil, dass außerhalb des Teilprogrammkontextes gewartet und der Prozess für andere Aufgaben frei wird.
Im folgenden Beispiel wird ein Abschnitt eines Teilprogramms, das im Dialog und asynchron ablaufen kann, mittels einer TAC-Queue gegen parallele Verarbeitung gesichert.
TAC tacqueue,TYPE=Q
Bild: Serialisierung von Teilprogrammen mit Hilfe von TAC-Queues
Für den nächsten Vorgang, der die kritische Strecke durchlaufen soll, wird mit DPUT eine Nachricht an die TAC-Queue geschickt. Erst mit erfolgreichem Transaktionsende wird der DPUT-Aufruf wirksam.
Der hier beschriebene Mechanismus muss initialisiert werden, damit die kritische Teilprogrammstrecke durchlaufen werden kann. Dies lässt sich z.B. beim Anwendungsstart über ein MSGTAC-Programm realisieren, das auf eine Startmeldung (K050, K051) reagiert und eine Nachricht für die TAC-Queue erzeugt.
Beispiel 6: Ausgabe fremder TLS-Blöcke im Dialog-Vorgang
Zugriffe auf TLS-Blöcke einer fremden Datenstation sind nur in Asynchron-Vorgängen erlaubt. Das Ausgeben von Daten aus fremden TLS-Blöcken aus einem Dialog-Vorgang heraus an die Datenstation ist mit geringer Modifikation von Beispiel 1 möglich:
Der Dialog-Vorgang gibt dem Hilfsvorgang zusätzlich den Namen des TLS-Blocks und des LTERMs mit. Der Hilfsvorgang liest mit einem GTDA-Aufruf die gewünschten Daten und schickt diese an die Temporäre Queue.
Der Dialog-Vorgang liest die TLS-Daten aus der Temporären Queue und gibt sie an der Datenstation aus.
Beispiel 7: Service-gesteuerte Queues als globale Speicherbereiche
Der Zugriff auf anwendungsglobale Speicherbereiche (GSSBs, siehe "Globaler Sekundärer Speicherbereich (GSSB)") ist nur seriell möglich, d.h. während des Lesens/Schreibens ist ein solcher Bereich gesperrt. Wenn an Stelle eines GSSB eine Temporäre Queue mit der "Browse"-Funktion verwendet wird, dann können mehrere Vorgänge parallel auf den Speicherbereich zugreifen.
Außerdem haben Temporäre Queues gegenüber GSSBs weniger Beschränkungen. Der Speicherbereich einer Temporären Queue ist nicht eingeschränkt (GSSB: 32767 Byte) und es sind mehr Queues als GSSBs erlaubt (500.000 gegenüber 32767).
Mit Hilfe einer Temporären Queue lässt sich z.B. eine Online-Auktion realisieren:
Mit DPUT QT/QE werden die Beschreibungen der Objekte nacheinander in eine Temporäre Queue gestellt. Für die Queue wird ein fester Name vergeben. Die Queue kann nachträglich erweitert werden.
Mit DGET BF/BN können diese Beschreibungen durch Interessenten gelesen werden, auch parallel durch mehrere Vorgänge.
Mit DGET PF/PN wird eine Beschreibung verarbeitet und damit aus der Queue genommen, z.B. nachdem ein Objekt versteigert wurde.
Nach Ende der Auktion wird die Temporäre Queue mit QREL gelöscht.
Per Generierung lässt sich die Anzahl der Nachrichten in einer Temporären Queue beschränken (KDCDEF-Anweisung QUEUE, Operand QLEV). Falls nur die neuesten Nachrichten interessant sind, dann kann der Wrap-Modus gewählt werden (QUEUE, Operand QMODE=WRAP-AROUND). Sobald der Maximalwert erreicht ist, wird mit jeder neuen Nachricht die jeweils älteste Nachricht gelöscht.