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_keyorderNumberを設定しています。これは、サブシナリオが完了し、トランザクションサーバからのコールバック要求のボディーに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