Compound Transaction
本チュートリアルでは、複数のシナリオを連携させるユースケースを紹介します。アプリケーションによっては、メインシナリオとサブシナリオに分割してそれぞれでトランザクション管理を行うような実装が必要になる特殊なケースがあります。Qmonus SDKのTransactionサービスは、コミット時に任意のURLにコールバックを送信するオプションを提供しています。以下のシーケンスのように、メインシナリオにおけるトランザクションの途中でサブシナリオを呼び出し、メイントランザクションをサスペンドさせ、サブシナリオ側でのトランザクションコミットを待ち受けてコールバックが来たらメイントランザクションをレジュームさせて処理継続させるといった連携が可能になります。
事前準備
メインシナリオとサブシナリオの両方のトランザクション名を生成するカウンターを作成します。
counter_name: sequenceNo
counter_type: number
counter_format: $
max_num: 999999
min_num: 1
padding: true
メインシナリオの作成
メインシナリオでは、サブシナリオへの呼び出しとサブシナリオの処理結果待ち受けを行います。サブシナリオの処理結果待ち受けは、serve
コマンドを使用する必要があります。
serve
コマンドは、コールバックを受け付ける任意のHTTPリクエストメソッドとHTTPリクエストパスを設定します。そして重要なのは、xname_key
です。コールバックによってレジュームするトランザクションを特定するため、コールバック要求にはトランザクション名が含まれている必要があります。コールバックを受信したserve
コマンドは、コールバック要求のリクエストボディーもしくはリクエストヘッダからxname_key
にマッチするキーをサーチしてその値をレジューム対象のトランザクション名と判断し、サスペンドしている該当トランザクションをロードしてシナリオのグローバルメモリを復元し、処理を再開します。
今回メインシナリオのserve
コマンドでは、xname_key
にorderNumber
を設定しています。これは、サブシナリオが完了し、トランザクションサーバからのコールバック要求のボディーにorderNumber
というキーで自身のトランザクション名が格納されているという前提に基づく設定です。ここでは、メインシナリオからサブシナリオのHTTP呼び出し要求ボディーにメインシナリオのトランザクション名をセットしておきます。また、serve
コマンドの待ち受けは、POST /mainScenarios/callback
をセットしておきます。
Note
ここで紹介しているコールバック連携は、Qmonus SDKのシナリオ相互だけの利用ではなく、異なるシステムとのインタラクションにおいてコールバック連携するケースにも対応できます。Qmonus SDKの外界との連携データには必ずその要求を一意に識別する情報が存在するため、その情報からトランザクションを特定できるように設計することでコールバック連携が可能になります。
category: Tutorial
name: mainScenario
uri: /mainScenarios
method: POST
commands:
- command: script
kwargs:
code: |-
context.logger.info("Start Main")
response = await callout(path="/subScenarios", method="POST", body={"orderNumber": context.axis.xname})
- command: serve
kwargs:
path: /mainScenarios/callback
method: POST
xname_key: orderNumber
aspect_options:
pre:
process: context.logger.info(context.request.dictionary)
- command: script
kwargs:
code: context.logger.info("End Main")
request_timeout: 60
connect_timeout: 60
spec:
response:
normal:
codes:
- 200
transaction:
enable: true
async: true
xname_use_counter: true
auto_begin: true
auto_response: true
xname: sequenceNo
xdomain: Tutorial
xtype: main
additional_paths: []
routing_auto_generation_mode: true
global_variables:
variable_groups: []
routing_options:
scope: local
サブシナリオの作成
サブシナリオでは、トランザクションコールバックオプションでメインシナリオが待ち受けているエンドポイントを設定します。また、xglobals_only_body
オプションをTrue
にすることでサブシナリオのグローバル変数のみをコールバックボディーにセットします。False
の場合は、サブシナリオのトランザクション情報もボディーに混入しますがここでは不要なので除去しておきます。サブシナリオのグローバル変数設定でメインから受け取ったリクエストボディーのorderNumber
値をグローバル変数に格納する設定を入れておくことで自動的にコールバックされます。
category: Tutorial
name: subScenario
uri: /subScenarios
method: POST
commands:
- command: script
kwargs:
code: context.logger.info("Start Sub")
- command: sleep
kwargs:
seconds: '3'
- command: script
kwargs:
code: context.logger.info("End Sub")
request_timeout: 60
connect_timeout: 60
spec:
response:
normal:
codes:
- 200
request:
body:
type: object
properties:
orderNumber:
type: string
required:
- orderNumber
transaction:
enable: true
async: true
xname_use_counter: true
auto_begin: true
auto_response: true
xname: sequenceNo
callback_options:
method: POST
url: /mainScenarios/callback
xglobals_only_body: true
xdomain: Tutorial
xtype: sub
routing_auto_generation_mode: true
global_variables:
orderNumber:
initial: context.request.body.orderNumber
description: Transaction name of parent scenario
routing_options:
scope: local
Note
メインシナリオからのcallout
で拡張ヘッダにX-Xaas-Callback-Url: /mainScenarios/callback
を設定した場合、サブシナリオのトランザクションコールバックオプションは省略できます。
Tip
コールバックが多重で送信されてくるような特殊なケースでは、同時に同じトランザクションをロードし、競合する可能性があります。その場合は、APIGWのコールバック用のルーティングにシリアルキューを設定することで要求を順次処理させることができます。
Note
サブシナリオからメインシナリオへのコールバックはAPIGWを経由しますので以下のようにコールバックパスへのルーティングを忘れず追加してください。
scope: secure
proxy:
scheme: 'http:'
path: /mainScenarios/callback
authorization:
auth_mode: axis
target:
scheme: 'http:'
path: /mainScenarios/callback
authorities:
- 'scenario:9000'
connect_timeout: 60
request_timeout: 60