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

AWS Step Functions で再実行（リドライブ）ができるようになったので、前回のシンプル編と集中と分散編にに引き続き、ジョブネットが親子構造（ネスト構造）を持っていると想定したときのエラー対応の挙動を試してみます。

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

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

# 想定するジョブネット
今回はジョブネットが親子構造を持っていると想定して実験します。今回は子ジョブ２が異常終了したときの挙動を確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/7f149c71-5047-4704-cc0d-6b07354d2768.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/8ac3198f-1471-7ca9-091d-17f28ec34366.png)
```
{
  "Comment": "This is a test state machine by yki",
  "StartAt": "StartAutomationWaitForCallBack (Parent Job 1)",
  "States": {
    "StartAutomationWaitForCallBack (Parent 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": "Step Functions StartExecution"
    },
    "Step Functions StartExecution": {
      "Type": "Task",
      "Resource": "arn:aws:states:::states:startExecution.sync:2",
      "Parameters": {
        "StateMachineArn": "arn:aws:states:us-east-1:0000000000:stateMachine:MyChildStateMachine-fdk35erfa",
        "Input": {
          "StatePayload": "Hello from Step Functions!",
          "AWS_STEP_FUNCTIONS_STARTED_BY_EXECUTION_ID.$": "$$.Execution.Id"
        }
      },
      "Next": "StartAutomationWaitForCallBack (Parent ob 3)"
    },
    "StartAutomationWaitForCallBack (Parent ob 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"
          ]
        }
      },
      "End": true
    }
  }
}
```

## 子ステートマシン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/80c7884c-c8af-70c6-bd2f-db3b09b056ac.png)
```
{
  "Comment": "This is a test state machine by yki",
  "StartAt": "StartAutomationWaitForCallBack (Child Job 1)",
  "States": {
    "StartAutomationWaitForCallBack (Child 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": "StartAutomationWaitForCallBack (Child Job 2)"
    },
    "StartAutomationWaitForCallBack (Child Job 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.sh"
          ]
        }
      },
      "Next": "StartAutomationWaitForCallBack (Child Job 3)"
    },
    "StartAutomationWaitForCallBack (Child 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"
          ]
        }
      },
      "End": true
    }
  }
}
```

なお、子ステートマシンを同期して実行するために権限設定が必要のため以下を参照しました。

https://dev.classmethod.jp/articles/aws-step-functions-startexecution-permissions/

エラーなく実行できることも確認済です。

## 親側のステートマシン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/b8fb4c5f-1fd6-807d-3a60-175cf2f345a1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/5104b899-ebaa-3ecc-20af-0f3c0b56adcd.png)


## 子側のステートマシン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/d7812eec-9945-4bf0-7da6-12fbae548964.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/b7d4ff4b-5c73-43a2-a3f1-c8daeda3eb2c.png)


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

想定通り子ジョブ２が異常終了となりました。

## 親側のステートマシン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/dd7b9373-2d83-1989-619d-e704ef945a04.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/e31815c2-ee36-2104-5288-a7ca21be436b.png)

## 子側のステートマシン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/80439525-edd4-992e-44b3-0697a4bc8026.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/6bf85083-b2f8-370c-1eb4-983f342caf30.png)

親側のステートマシンをリドライブするのか、子側のステートマシンをリドライブするのかで挙動が変わりそうですね。両方とも実験してみましょう。

# ケース１：親側のステートマシンからリドライブ
まずは親側のステートマシンからリドライブしてみます。子ステートマシン全体が再実行されそうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/28e58142-1175-fc41-49f3-2b8b2cef2d9f.png)

親側からリドライブをすると、予想通り子ステートマシンについては新たに全体が実行されることになりました。先ほど失敗した実行はそのまま失敗として残っています。

## 親側のイベント
親側のイベントは以下の通り、リドライブがなされていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/d4184157-fab1-cd63-bb06-89ea4e697f48.png)

## 子側のイベント
子側のイベントは以下の通りで、初回の異常終了が起こった実行はそのままで、新たにステートマシンが実行されています。

### 初回の実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/41de61f1-c9eb-a13c-2919-4972e8bed4ec.png)

### リドライブによる実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/1ab8c2bc-a717-dc3e-c655-bb1b897ea20f.png)

# ケース２： 子側のステートマシンからリドライブ
次に改めて異常終了を発生させて、子側のステートマシンでリドライブを行ってみます。異常終了したジョブから再実行がされそうですね。親側のステートマシンがどうなるか気になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/62d1ded2-0ccc-a96d-d3eb-78924bcbf75e.png)

リカバリを行った後、子側からリドライブをすると当然なが子側のステートマシンは子ジョブ２と子ジョブ３が実行されて、すべて正常終了となりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/1b8cbc2f-a648-6d2f-822f-917d18e20d4b.png)

子側のステートマシンがすべて正常実行完了後に、元々の親側のステートマシンを見に行くと、異常終了で止まったままでした。これは困りますね。もしここで親側でリドライブすると、また子側のステートマシンが再実行されてしまうので子側のステートマシンをリドライブするのは避けた方が良さそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623605/321284f4-96c0-076a-f6e0-2e73236200f1.png)


ということで今回は親子構造を持ったジョブネットを想定して、AWS Step Functions の再実行を試してみました。