ジョブネットを想定して AWS Step Functions の再実行パターンを試してみた（２）集中と分散編

AWS Step Functions で再実行ができるようになったので、前回のシンプル編に引き続き、ジョブネットのエラー対応をどれだけ実現できるか試してみます。

https://qiita.com/yki/items/a3bffa39f4bed5cdd0fb

# 想定するジョブネット

今回はジョブが選択と分岐の形状と想定をして実験してみます。今回は**ジョブ２－２**と**ジョブ４－２**がそれぞれ異常終了したときの挙動を確認します。また、異常終了したジョブと並行して実行されるジョブ（ジョブ２－１や４－１）の**完了タイミングが、異常終了の前になるか後になるかで多少の挙動の違い**があるためそこも実験していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/c69b313f-2625-c915-56db-253b8796f59b.png)

# 実装の概要
前回と同じくaws-samples の [amazon-stepfunctions-ssm-waitfortasktoken](https://github.com/aws-samples/amazon-stepfunctions-ssm-waitfortasktoken) を利用した SfnRunCommandByInstanceIds を用いて、Steps Functions に以下のようなステートマシンを定義しました。並行稼働部は Parallel を使用しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/2749f2e5-fc34-9116-5a3a-fd427a6d7850.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-xxxxxxxxxxxxxxxxx"
          ],
          "taskToken.$": "States.Array($$.Task.Token)",
          "workingDirectory": [
            "/home/ec2-user/sample-batch/"
          ],
          "Commands": [
            "./do-some1.sh"
          ]
        }
      },
      "Next": "Parallel"
    },
    "Parallel": {
      "Type": "Parallel",
      "Next": "StartAutomationWaitForCallBack (Job 3)",
      "Branches": [
        {
          "StartAt": "StartAutomationWaitForCallBack (Job 2-1)",
          "States": {
            "StartAutomationWaitForCallBack (Job 2-1)": {
              "Type": "Task",
              "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
              "Parameters": {
                "DocumentName": "SfnRunCommandByInstanceIds",
                "Parameters": {
                  "InstanceIds": [
                    "i-xxxxxxxxxxxxxxxxx"
                  ],
                  "taskToken.$": "States.Array($$.Task.Token)",
                  "workingDirectory": [
                    "/home/ec2-user/sample-batch/"
                  ],
                  "Commands": [
                    "./do-some2-1.sh"
                  ]
                }
              },
              "End": true
            }
          }
        },
        {
          "StartAt": "StartAutomationWaitForCallBack (Job 2-2)",
          "States": {
            "StartAutomationWaitForCallBack (Job 2-2)": {
              "Type": "Task",
              "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
              "Parameters": {
                "DocumentName": "SfnRunCommandByInstanceIds",
                "Parameters": {
                  "InstanceIds": [
                    "i-xxxxxxxxxxxxxxxxx"
                  ],
                  "taskToken.$": "States.Array($$.Task.Token)",
                  "workingDirectory": [
                    "/home/ec2-user/sample-batch/"
                  ],
                  "Commands": [
                    "./do-some2-2.sh"
                  ]
                }
              },
              "End": true
            }
          }
        }
      ]
    },
    "StartAutomationWaitForCallBack (Job 3)": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
      "Parameters": {
        "DocumentName": "SfnRunCommandByInstanceIds",
        "Parameters": {
          "InstanceIds": [
            "i-xxxxxxxxxxxxxxxxx"
          ],
          "taskToken.$": "States.Array($$.Task.Token)",
          "workingDirectory": [
            "/home/ec2-user/sample-batch/"
          ],
          "Commands": [
            "./do-some3.sh"
          ]
        }
      },
      "Next": "Parallel (1)"
    },
    "Parallel (1)": {
      "Type": "Parallel",
      "End": true,
      "Branches": [
        {
          "StartAt": "StartAutomationWaitForCallBack (Job 4-1)",
          "States": {
            "StartAutomationWaitForCallBack (Job 4-1)": {
              "Type": "Task",
              "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
              "Parameters": {
                "DocumentName": "SfnRunCommandByInstanceIds",
                "Parameters": {
                  "InstanceIds": [
                    "i-xxxxxxxxxxxxxxxxx"
                  ],
                  "taskToken.$": "States.Array($$.Task.Token)",
                  "workingDirectory": [
                    "/home/ec2-user/sample-batch/"
                  ],
                  "Commands": [
                    "./do-some4-1.sh"
                  ]
                }
              },
              "End": true
            }
          }
        },
        {
          "StartAt": "StartAutomationWaitForCallBack (Job 4-2)",
          "States": {
            "StartAutomationWaitForCallBack (Job 4-2)": {
              "Type": "Task",
              "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
              "Parameters": {
                "DocumentName": "SfnRunCommandByInstanceIds",
                "Parameters": {
                  "InstanceIds": [
                    "i-xxxxxxxxxxxxxxxxx"
                  ],
                  "taskToken.$": "States.Array($$.Task.Token)",
                  "workingDirectory": [
                    "/home/ec2-user/sample-batch/"
                  ],
                  "Commands": [
                    "./do-some4-2.sh"
                  ]
                }
              },
              "End": true
            }
          }
        }
      ]
    }
  }
}
```

エラーなく実行できることも確認済です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/22a1184a-1440-6f76-e1ba-ab0a01dfe87b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/d1b5c8c4-3578-046a-65d6-6c6595a45f1b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/4db6cb7f-9858-dd7e-fb9d-309b96fcd8d7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/6ea2b12b-ba50-2aa5-06ec-84ff5f350b12.png)


# ジョブ２－２の異常終了と再実行
## 異常終了
異常終了が発生するように`touch /home/ec2-user/sample-batch/filetest2-2` と`touch /home/ec2-user/sample-batch/filetest4-2` を行ってからステートマシンの実行を行います。

想定通りジョブ2-1が異常終了となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/89bf6609-caf2-12b5-eb8b-a9c06d1f7460.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/4bb63b12-92ab-46fd-521f-b60f4d376602.png)


ここでリカバリ対応として`rm /home/ec2-user/sample-batch/filetest2-2`をしてからリドライブを行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/5d1c4c9f-20c5-ae34-6a93-0fd048831497.png)


異常終了したジョブ２－２とその後続のジョブが実行されてました。その上で、予定通りジョブ４－２が異常終了しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/343a038e-e0cc-5c8c-7787-1dad596288ba.png)

# さらにジョブ４－２の異常終了と再実行
リカバリ対応として`rm /home/ec2-user/sample-batch/filetest4-2`をしてからリドライブを行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/4d9a90d1-b245-d9f6-d46f-da5d54a841e1.png)


無事にジョブ４－２が再実行されて正常終了となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/5ac89c54-7103-b86d-cf23-f36655dc17f1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/dd1596e4-7945-1255-778a-d7c37a05daee.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/c8510f8c-e010-5037-dbd7-aa392983bcdf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/2c3aed04-768c-38e6-77c8-086ece4562b9.png)

# 異常終了する前に並行稼働ジョブが完了していない場合
上記の例では、例えばジョブ２－２が異常終了する前にジョブ２－１は正常終了していましたが、そうではない場合のケースも確認します。

ジョブ２－１の実行時間を延長し、ジョブ２－２より先に終わらないようにした上で、先ほどと同じステートマシンを実行します。ジョブ２－２は異常終了するように仕込んであります。すると結果として、ジョブ２－２は予定通り失敗となりましたが、ジョブ２－１はキャンセル済みという状態となりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/33e16a68-7745-4d3f-aab9-b01f7f0a8c10.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/d9aefa2b-5288-1ba9-0e08-ca1c7d331a96.png)

この状態でリカバリ対応を行った後にステートマシンのリドライブをしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/97a32e76-531a-5e6f-15c3-92446f4797e2.png)

すると先ほどの実験とは異なり、ジョブ２－１とジョブ２－２の両方が再実行されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/89a4c64b-b86c-d54f-8a12-243bf8de2557.png)

ジョブ２－１の構造によっては、再実行されたりされなかったりというのは困るため、以下のように工夫をする必要がありそうです。これはちょっと不便ですね。

https://qiita.com/naoaki-yzrh/items/2341dd7002e9c8c97512

## 補足：キャンセル済みとはどんな状態か
以下の記事で検証されているように、キャンセルとは単純に呼び出し元の Step Functions 上のお話のようです。

https://dev.classmethod.jp/articles/step-functions-state-machine-set-timeoutseconds/