ジョブネットを想定してAWS Step Functions の再実行パターンを試してみた（１）シンプル編

AWS Step Functions で再実行ができるようになったので、ジョブネットのエラー対応をどれだけ実現できるか試してみます。まずはシンプルなステートマシンを使用して確認します。

https://aws.amazon.com/jp/about-aws/whats-new/2023/11/aws-step-functions-restarting-workflows-failure/

# 想定するジョブネット

説明をわかりやすくするために、用語は以下の通りとします。

実行する処理をジョブと呼びます。ジョブはシェルスクリプトで実装されていて、EC2上で稼働する前提とします。そして、複数のジョブをつなげて実行する塊をジョブネットと呼びます。

本記事で想定するジョブネットは以下とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/be0f9811-4b5b-6589-162c-0ac84527c702.png)


# ジョブネット再実行のパターン

本記事では以下の基本的な3パターンの実装を試みてみます。**結論としてパターン１とパターン３は Step Functions の再実行機能を用いて簡単に手動再実行できますが、パターン２はあらかじめステートマシンの定義を工夫して自動処理としておくなどの対応が必要です。**
1. 異常終了したジョブから再実行
2. 異常終了したジョブの次から再実行
3. 異常終了したジョブが含まれるジョブネット全体を再実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/4d1e54b3-7e87-3dd3-2cc8-082dce1f4f93.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/a8d908af-cdc4-9d0b-7f97-03c0e3495036.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/a1414ccf-bc2b-215c-11d5-8bf499119f51.png)

# 実装の概要
aws-samples の [amazon-stepfunctions-ssm-waitfortasktoken](https://github.com/aws-samples/amazon-stepfunctions-ssm-waitfortasktoken) を利用した SfnRunCommandByInstanceIds を用いて Steps Functions に以下のようなステートマシンを定義しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/bb366766-053c-22ea-fd4e-c6e92cc240f2.png)

```
{
  "Comment": "This is a test state machine by yki",
  "StartAt": "StartAutomationWaitForCallBack (Job 1)",
  "States": {
    "StartAutomationWaitForCallBack (Job 1)": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
      "Parameters": {
        "DocumentName": "SfnRunCommandByInstanceIds",
        "Parameters": {
          "InstanceIds": [
            "i-xxxxxxxxxxxxxxxxxx"
          ],
          "taskToken.$": "States.Array($$.Task.Token)",
          "workingDirectory": [
            "/home/ec2-user/sample-batch/"
          ],
          "Commands": [
            "./do-some1.sh"
          ]
        }
      },
      "Next": "StartAutomationWaitForCallBack (Job 2)"
    },
    "StartAutomationWaitForCallBack (Job 2)": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
      "Parameters": {
        "DocumentName": "SfnRunCommandByInstanceIds",
        "Parameters": {
          "InstanceIds": [
            "i-xxxxxxxxxxxxxxxxxx"
          ],
          "taskToken.$": "States.Array($$.Task.Token)",
          "workingDirectory": [
            "/home/ec2-user/sample-batch/"
          ],
          "Commands": [
            "./do-some2.sh"
          ]
        }
      },
      "Next": "StartAutomationWaitForCallBack (Job 3)"
    },
    "StartAutomationWaitForCallBack (Job 3)": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
      "Parameters": {
        "DocumentName": "SfnRunCommandByInstanceIds",
        "Parameters": {
          "InstanceIds": [
            "i-xxxxxxxxxxxxxxxxxx"
          ],
          "taskToken.$": "States.Array($$.Task.Token)",
          "workingDirectory": [
            "/home/ec2-user/sample-batch/"
          ],
          "Commands": [
            "./do-some3.sh"
          ]
        }
      },
      "End": true
    }
  }
}
```

エラーなく実行できることも確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/78444e59-07bc-4fd6-1ea9-08eacd1798cd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/42720949-4db3-606a-9803-4be03bbc43d2.png)

なお、使用しているシェルは以下のように filetest2というファイルがあるとエラーを返すように実装しています。
```
#!/bin/bash
if [ $# -ne 0 ]; then
        echo "引数は$#個です" 1>&2
        echo "引数を指定してはいけません" 1>&2
        exit 1
fi
for i in {1..3} ; do
        echo "Doing Something #2" ${i}
        sleep 1
done
if [ -f ./filetest2 ]; then
        exit 1
fi
exit 0

```

## パターン１：異常終了したジョブから再実行
これが今回できるようになったパターンですね。ジョブ２をエラーとするために `touch /home/ec2-user/sample-batch/filetest2` でファイルを作ってから上記のステートマシンを実行します。

想定通りジョブ２がエラーとなりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/dd9a60e1-edc4-53e6-58df-b7d06ef76aac.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/453251df-e899-5d99-ab3c-34a59a9d8daf.png)

ここでリカバリ対応として`rm /home/ec2-user/sample-batch/filetest2`をしてから、ステートマシンに対してリドライブを指示します。リドライブはマネジメントコンソールの以下の画面から行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/9705a878-922b-4c78-ecca-956b4ee3ffb5.png)
以下のような確認ダイアログが表示されます。確かにジョブ２から再実行と表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/1be16b51-fd98-6679-67ff-ed1e11e3de88.png)
ちなみに、同じくマネジメントコンソールの以下の部分からもリドライブが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/413b1961-3037-61e3-6cd5-19cc908045f9.png)


無事にジョブ２の再実行とジョブ３の実行が行われました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/bbff991e-ef53-a08f-75a8-f50ab252a502.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/a2adff62-66cd-f948-e257-199ed884f549.png)


## パターン２：異常終了したジョブの次から再実行
前述の通り、リドライブをするとジョブ２も再実行されてしまうので事後対応はできません。 事前に Step functions のステートマシン定義にエラーをキャッチして次のアクションに進むように定義をしておく必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/d4a8dabb-739e-be5b-3329-f01e22843ddf.png)
具体的にはジョブ２のアクションの「エラーをキャッチ」の設定で "Statues.TaskFailed" をキャッチして次のアクションであるジョブ３に進むよう定義しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/3e2e5608-3622-0497-0354-edb9fcc38cc2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/00c876d5-6049-dd42-6af3-ff6318a3c3e5.png)

この定義を行っておくと、ジョブ２がエラーとなる状態でステートマシンを実行しても、ステートマシン全体としては成功となりますが、ジョブ２のアクションは「キャッチされたエラー」として表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/3e2265d0-5170-ae3e-bfba-913308a45f83.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/2ce9c257-1906-bd7f-1580-2d1947e65bf0.png)

ただ、この設定をステートマシンにしてしまうとリドライブができません。現時点では実行したい処理のエラー対応要件によって使い分けるしかないかと思います。

## パターン３：異常終了したジョブが含まれるジョブネット全体を再実行
これは以前から実現できていました。単純に新たにステートマシンを実行することとなります。先ほどと同じくジョブ２がエラー停止した状態とした上で、マネジメントコンソールの "Recovery"の "Start New Execution" から再度ステートマシン全体を実行可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/9685a59d-2791-09d7-ad78-2205310c40b0.png)

新たに実行を開始する画面が表示されるため「実行を開始」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/34ba0f46-532f-854e-32d1-81620189805b.png)

なお、この方法だと「失敗」ステータスとなった実行は失敗のまま残ることとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/b757752e-fe33-45b6-9a02-e44632db41e7.png)


本記事では AWS Step Functions の再実行パターンをシンプルなステートマシンを用いて確認してみました。リドライブができることでこれまで以上に Step Functions の用途が広がることになると思います。