AWS Step FunctionsのParallelステートを使って並列実行させる

eyecatch_step_functions

AWS re:Invent 2016で発表された、ビジュアルワークフローを用いて分散アプリケーションを構築するサービス『AWS Step Functions』。 今回は Parallel ステートを使って並列実行させる方法を紹介します。 メッセージ・キューで言うところの Fan-Out 的な用途に用います。

なお Step Functions が対応しているステートは以下です。

  • Task
  • Wait
  • Pass
  • Succeed
  • Fail
  • Choice
  • Parallel

Parallel ステートを使った並列実行:サンプル 1

Step Functions の "Parallel State" ブループリントです。

parallel-blue-print

入力が

  1. 20 秒待つステート
  2. Pass ステートのあと 10秒待つステート

に分岐し、全分岐が完了すると Final State に遷移します。

待ち時間が異なるため、各分岐の終了タイミングはことなりますが、分岐の次のステートに遷移するのは、全分岐が終了してからであることに注意して下さい。

ブループリントの Amazon States Language

対応する Amazon States Language は以下です。

{
  "Comment": "An example of the Amazon States Language using a parallel state to execute two branches at the same time.",
  "StartAt": "Parallel",
  "States": {
    "Parallel": {
      "Type": "Parallel",
      "Next": "Final State",
      "Branches": [
        {
          "StartAt": "Wait 20s",
          "States": {
            "Wait 20s": {
              "Type": "Wait",
              "Seconds": 20,
              "End": true
            }
          }
        },
        {
          "StartAt": "Pass",
          "States": {
            "Pass": {
              "Type": "Pass",
              "Next": "Wait 10s"
            },
            "Wait 10s": {
              "Type": "Wait",
              "Seconds": 10,
              "End": true
            }
          }
        }
      ]
    },
    "Final State": {
      "Type": "Pass",
      "End": true
    }
  }
}

Branches のリスト内で記述している内容が並列実行処理です。

実行例

ステートマシン作成後は "New execution" から実行します。 ステートマシンはインプットに依存しないため、デフォルトのインプットのままステートマシンを実行します。

parallel-blue-print-result

分岐後のステートの Final State のインプットには、Amazon State Language の Branches で定義した分岐に対応する Output がリスト形式で渡ります。

Parallel ステートを使った並列実行:サンプル 2

Step Functions の Developer マニュアルの Parallel ステートのサンプルです。 parallel-calc

2つの整数をインプットとして受け取り、そのインプットをもとに

  • 足し算(Add)
  • 引き算(Subtract)

を行い、結果を NextState に渡します。

Lambda 関数の実装

  • Add
  • Subtract

の Lambda 関数 はそれぞれ以下の通りです。

Add Lambda Function

def lambda_handler(event, context):
    return event[0] + event[1]

Subtract Lambda Function

def lambda_handler(event, context):
    return event[0] - event[1]

ブループリントの Amazon States Language

対応する Amazon States Language は以下です。

{
  "Comment": "Parallel Sample",
  "StartAt": "FunWithMath",
  "States": {
    "FunWithMath": {
      "Type": "Parallel",
      "Branches": [
        {
          "StartAt": "Add",
          "States": {
            "Add": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:REGION:12345:function:Add",
              "End": true
            }
          }
        },
        {
          "StartAt": "Subtract",
          "States": {
            "Subtract": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:REGION:12345:function:Subtract",
              "End": true
            }
          }
        }
      ],
      "Next": "NextState"
    },
  "NextState": {
      "Type": "Pass",
    "End": true
  }
  }
}

実行例

ステートマシン作成後は "New execution" から実行します。

parallel-calc-output

[2, 3]

というインプットに対して Add/Subtract それぞれでの計算結果が NextState にリスト形式で渡っています。

[5,-1]

Parallel の注意点

一部の並列処理が失敗した時

並列処理したブランチの一部が失敗すると、並列処理全体が失敗とみなされるため、進行中の処理は停止させられます。

If any branch fails, due to either an unhandled error or by transitioning to a Fail state, the entire Parallel state is considered to have failed and all its branches are stopped. If the error is not handled by the Parallel state itself, Step Functions will stop the execution with an error. http://docs.aws.amazon.com/step-functions/latest/dg/awl-ref-states-parallel.html

次の様に必ず失敗するブランチを含んだ Parallel を用意し、実行すると

{
  "Comment": "An example of partially failed branch pattern",
  "StartAt": "Parallel",
  "States": {
    "Parallel": {
      "Type": "Parallel",
      "Next": "Final State",
      "Branches": [
        {
          "StartAt":"Wait 5s",
          "States": {
            "Wait 5s": {
              "Type": "Wait",
              "Seconds": 10,
              "Next": "Fail"
            },
            "Fail":{
              "Type":"Fail",
              "Cause":"Who Cares"
            }
          }
        },
        {
          "StartAt": "Wait 20s",
          "States": {
            "Wait 20s": {
              "Type": "Wait",
              "Seconds": 20,
              "End": true
            }
          }
        },
        {
          "StartAt": "Pass",
          "States": {
            "Pass": {
              "Type": "Pass",
              "Next": "Wait 10s"
            },
            "Wait 10s": {
              "Type": "Wait",
              "Seconds": 10,
              "End": true
            }
          }
        }
      ]
    },
    "Final State": {
      "Type": "Pass",
      "End": true
    }
  }
}

次の図のように wait 状態だった処理はキャンセル(グレー背景)されています。

parallel-partial-failure

Parallel から次の状態へ繊維するタイミング

並列実行されたタスクはタスク毎に処理時間が異なります。全部ランチが完了して初めて次のステートに遷移します。

A Parallel state causes AWS Step Functions to execute each branch, starting with the state named in that branch's StartAt field, as concurrently as possible, and wait until all branches terminate (reach a terminal state) before processing the Parallel state's Next field.

http://docs.aws.amazon.com/step-functions/latest/dg/awl-ref-states-parallel.html

まとめ

今回は Parallel ステートによる並列実行方法を紹介しました。

Fan-Out のように、一つの入力に対して複数の異なる処理を行い、かつその状態も管理したいようなケースにおいて非常に有用かと思います。

面白いユースケースが見つかれば、ご紹介したいと思います。

参考