[AWS Step Functions] 名前のプレフィックスが一致するEventBridgeルールを一定期間有効化や無効化するステートマシンを作成してみた

AWS Step Functionsなら一定期間EventBridgeルール有効化や無効化する処理も簡単に実装できます。
2022.02.10

一定期間EventBridgeルールを有効化もしくは無効化しておきたい

こんにちは、のんピ(@non____97)です。

皆さんは一定期間EventBridgeルールを有効化や無効化したいと思ったことはありますか? 私はあります。

例えばメンテナンスをしており、EventBridgeルールのターゲットが必ず失敗する場面では、ターゲットを実行したくないと考えると思います。そのような場合の対応方法として、EventBridgeルールを無効化することが挙げられます。

しかし、EventBridgeルールを手動で無効化すると、メンテナンス明けに有効化し忘れるリスクがあります。

そこで、名前のプレフィックスが一致するEventBridgeルールを一定期間有効化や無効化するステートマシンを作成して、楽したいと思います。

こちらのステートマシンはAWS CDKを使って、簡単にデプロイできるようにしています。こちらのコードのリポジトリは以下になります。

ステートマシンの構成

ステートマシンは以下の通り2つ用意しています。

  1. 複数のEventBridgeルールを有効化もしくは無効化をするステートマシン (EnableOrDisableEventBridgeRulesStateMachine)
  2. 1.のステートマシンを実行するステートマシン (ChangeStatusEventBridgeRulesStateMachine)

なんでステートマシンを2つ作成しているの?」と思われるかもしれません。これはEventBridgeルールの「有効化」、「無効化」と同じような処理を何度も定義しないようにするためです。

処理のパターンは以下の2パターンです。

  1. 一定期間EventBridgeルールを有効化 :
    • EventBridgeルールを有効化するまで待機
    • 複数のEventBridgeルールを有効化
    • EventBridgeルールを無効化するまで待機
    • 複数のEventBridgeルールを無効化
  2. 一定期間EventBridgeルールを無効化 :
    • EventBridgeルールを無効化するまで待機
    • 複数のEventBridgeルールを無効化
    • EventBridgeルールを有効化するまで待機
    • 複数のEventBridgeルールを有効化

以上の通り、同じような処理が繰り返されていることがわかります。

1つのステートマシンで愚直にこの処理を実装しようとすると、同じような処理を何度も定義する必要があります。そのため、以下のような処理を行うステートマシンを定義してあげます。

  • EventBridgeルールを有効化もしくは無効化するまで待機
  • 複数のEventBridgeルールを有効化もしくは無効化

図で表すと、以下のようになります。

複数のEventBridgeルールを有効化もしくは無効化をするステートマシン

こちらのステートマシンを呼び出す定義を以下2パターン分してあげます。

  1. 一定期間EventBridgeルールを有効化
    1. 複数のEventBridgeルールを有効化もしくは無効化をするステートマシンを呼び出す
    2. 複数のEventBridgeルールを有効化もしくは無効化をするステートマシンを呼び出す
  2. 一定期間EventBridgeルールを無効化
    1. 複数のEventBridgeルールを有効化もしくは無効化をするステートマシンを呼び出す
    2. 複数のEventBridgeルールを有効化もしくは無効化をするステートマシンを呼び出す

ステートマシンを呼び出す際は、有効化なのか無効化なのかを判断するパラメーターを渡してあげます。

図で表すと、以下のようになります。

複数のEventBridgeルールを有効化もしくは無効化をするステートマシンを管理するステートマシン

ちなみに各ステートマシンの定義は以下の通りです。

EnableOrDisableEventBridgeRulesStateMachine

{
  "StartAt": "isTimestamp",
  "States": {
    "isTimestamp": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$$.Execution.Input.WaitTime.isTimestamp",
          "BooleanEquals": true,
          "Next": "WaitTimestamp"
        }
      ],
      "Default": "WaitSeconds"
    },
    "WaitSeconds": {
      "Type": "Wait",
      "SecondsPath": "$.WaitTime.Value",
      "Next": "ListRules"
    },
    "ListRules": {
      "Next": "isEnableRules",
      "Type": "Task",
      "ResultPath": "$",
      "Resource": "arn:aws:states:::aws-sdk:eventbridge:listRules",
      "Parameters": {
        "NamePrefix.$": "$$.Execution.Input.EventBridgeRule.NamePrefix",
        "EventBusName.$": "$$.Execution.Input.EventBridgeRule.EventBusName"
      }
    },
    "WaitTimestamp": {
      "Type": "Wait",
      "TimestampPath": "$.WaitTime.Value",
      "Next": "ListRules"
    },
    "isEnableRules": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$$.Execution.Input.isEnableRules",
          "BooleanEquals": true,
          "Next": "EnableRuleMap"
        }
      ],
      "Default": "DisableRuleMap"
    },
    "DisableRuleMap": {
      "Type": "Map",
      "End": true,
      "Iterator": {
        "StartAt": "DisableRule",
        "States": {
          "DisableRule": {
            "End": true,
            "Type": "Task",
            "Resource": "arn:aws:states:::aws-sdk:eventbridge:disableRule",
            "Parameters": {
              "Name.$": "$.Name",
              "EventBusName.$": "$$.Execution.Input.EventBridgeRule.EventBusName"
            }
          }
        }
      },
      "ItemsPath": "$.Rules"
    },
    "EnableRuleMap": {
      "Type": "Map",
      "End": true,
      "Iterator": {
        "StartAt": "EnableRule",
        "States": {
          "EnableRule": {
            "End": true,
            "Type": "Task",
            "Resource": "arn:aws:states:::aws-sdk:eventbridge:enableRule",
            "Parameters": {
              "Name.$": "$.Name",
              "EventBusName.$": "$$.Execution.Input.EventBridgeRule.EventBusName"
            }
          }
        }
      },
      "ItemsPath": "$.Rules"
    }
  }
}

ChangeStatusEventBridgeRulesStateMachine

{
  "StartAt": "isEnableToDisable",
  "States": {
    "isEnableToDisable": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$$.Execution.Input.isEnableToDisable",
          "BooleanEquals": true,
          "Next": "StartExecutionStateMachineToEnableRules1"
        }
      ],
      "Default": "StartExecutionStateMachineToDisableRules1"
    },
    "StartExecutionStateMachineToDisableRules1": {
      "Next": "StartExecutionStateMachineToEnableRules2",
      "Type": "Task",
      "Resource": "arn:aws:states:::states:startExecution.sync:2",
      "Parameters": {
        "Input": {
          "EventBridgeRule.$": "$$.Execution.Input.EventBridgeRule",
          "WaitTime.$": "$$.Execution.Input.DisableWaitTime",
          "isEnableRules": false
        },
        "StateMachineArn": "arn:aws:states:us-east-1:<AWSアカウントID>:stateMachine:EnableOrDisableEventBridgeRulesStateMachine9A1900B2-Si0PdHxNfdDg"
      }
    },
    "StartExecutionStateMachineToEnableRules2": {
      "End": true,
      "Type": "Task",
      "Resource": "arn:aws:states:::states:startExecution.sync:2",
      "Parameters": {
        "Input": {
          "EventBridgeRule.$": "$$.Execution.Input.EventBridgeRule",
          "WaitTime.$": "$$.Execution.Input.EnableWaitTime",
          "isEnableRules": true
        },
        "StateMachineArn": "arn:aws:states:us-east-1:<AWSアカウントID>:stateMachine:EnableOrDisableEventBridgeRulesStateMachine9A1900B2-Si0PdHxNfdDg"
      }
    },
    "StartExecutionStateMachineToEnableRules1": {
      "Next": "StartExecutionStateMachineToDisableRules2",
      "Type": "Task",
      "Resource": "arn:aws:states:::states:startExecution.sync:2",
      "Parameters": {
        "Input": {
          "EventBridgeRule.$": "$$.Execution.Input.EventBridgeRule",
          "WaitTime.$": "$$.Execution.Input.EnableWaitTime",
          "isEnableRules": true
        },
        "StateMachineArn": "arn:aws:states:us-east-1:<AWSアカウントID>:stateMachine:EnableOrDisableEventBridgeRulesStateMachine9A1900B2-Si0PdHxNfdDg"
      }
    },
    "StartExecutionStateMachineToDisableRules2": {
      "End": true,
      "Type": "Task",
      "Resource": "arn:aws:states:::states:startExecution.sync:2",
      "Parameters": {
        "Input": {
          "EventBridgeRule.$": "$$.Execution.Input.EventBridgeRule",
          "WaitTime.$": "$$.Execution.Input.DisableWaitTime",
          "isEnableRules": false
        },
        "StateMachineArn": "arn:aws:states:us-east-1:<AWSアカウントID>:stateMachine:EnableOrDisableEventBridgeRulesStateMachine9A1900B2-Si0PdHxNfdDg"
      }
    }
  }
}

やってみた

一定期間EventBridgeルールを有効化

それではステートマシンをnpx cdk deployでデプロイして、ステートマシンを実行してみます。

まずは、一定期間EventBridgeルールを有効化するパターンから試します。

ステートマシン実行前のEventBridgeルールは以下のような状態です。名前がStateMachineTest001-から始まるEventBridgeルールを無効化しています。

一定期間EventBridgeルールを有効化前のEventBridgeルールの状態

以下パラメーターを入力してステートマシンを実行します。

{
  "EnableWaitTime": {
    "Value": 5,                             // 5秒後にEventBridgeルールを有効化
    "isTimestamp": false                    // タイムスタンプではなく秒数を指定
  },
  "DisableWaitTime": {
    "Value": 10,                            // 10秒後にEventBridgeルールを有効化
    "isTimestamp": false                    // タイムスタンプではなく秒数を指定
  },
  "isEnableToDisable": true,                // EventBridgeルールを有効化 -> 無効化の順番でステータスを変更
  "EventBridgeRule": {
    "NamePrefix": "StateMachineTest001-",   // 名前が "StateMachineTest001-" から始まるEventBridgeルール
    "EventBusName": "default"               // EventBridgeルールが存在するEventBridge Bus
  }
}

ステートマシンを実行して数秒待つと、名前がStateMachineTest001-から始まるEventBridgeルールが有効化されました。

一定期間EventBridgeルールを有効化 - EventBridgeルールの有効化

さらに数秒待つと、有効化されたEventBridgeルールが無効化されました。

一定期間EventBridgeルールを有効化 - EventBridgeルールの無効化

ステートマシンのステータスを確認すると、実行ステータスが成功になっていました。

一定期間EventBridgeルールを有効化 - ステートマシンの実行ステータス確認

意図した期間EventBridgeルールが有効化されていたか確認するために、AWS X-Rayのトレースマップを見てみます。トレースマップを見てみると、パラメーターで指定した通り、5秒待機した後にEventBridgeルールが有効化され、その10秒後に無効化されたことが確認できます。

一定期間EventBridgeルールを有効化 - AWS X-Rayのトレースマップ

一定期間EventBridgeルールを無効化

次に一定期間EventBridgeルールを無効化するパターンを試します。

ステートマシン実行前のEventBridgeルールは以下のような状態です。名前がStateMachineTest001-から始まるEventBridgeルールを有効化しています。

一定期間EventBridgeルールを無効化前のEventBridgeルールの状態

以下パラメーターを入力してステートマシンを実行します。

{
  "DisableWaitTime": {
    "Value": "2022-02-10T02:30:00Z",        // 2022-02-10 02:30:00 (UTC) にEventBridgeルールを無効化
    "isTimestamp": true                     // タイムスタンプを指定
  },
  "EnableWaitTime": {
    "Value": "2022-02-10T02:31:00Z",        // 2022-02-10 02:31:00 (UTC) にEventBridgeルールを有効化                   
    "isTimestamp": true                     // タイムスタンプを指定
  },
  "isEnableToDisable": false,               // EventBridgeルールを無効化 -> 有効化の順番でステータスを変更
  "EventBridgeRule": {
    "NamePrefix": "StateMachineTest001-",   // 名前が "StateMachineTest001-" から始まるEventBridgeルール
    "EventBusName": "default"               // EventBridgeルールが存在するEventBridge Bus
  }
}

日本時間の11:30になると、名前がStateMachineTest001-から始まるEventBridgeルールが有効化されました。また、日本時間の11:31になると、名前がStateMachineTest001-から始まるEventBridgeルールが無効化されました。 (画面キャプチャは代わり映えしないので割愛します)

ステートマシンのステータスを確認すると、実行ステータスが成功になっていました。

一定期間EventBridgeルールを無効化 - ステートマシンの実行ステータス確認

意図した期間EventBridgeルールが無効化されていたか確認するために、AWS X-Rayのトレースマップを見てみます。トレースマップを見てみると、パラメーターで指定した通り、しばらく待機した後にEventBridgeルールが無効化され、その約1分後に有効化されたことが確認できます。

一定期間EventBridgeルールを無効化 - AWS X-Rayのトレースマップ

AWS Step Functionsはやっぱり便利

名前のプレフィックスが一致するEventBridgeルールを一定期間有効化や無効化するステートマシンを作成してみました。

AWS Step Functionsを使えば、Lambdaも使わず簡単に実装できます。

なお、ステートマシンの最大実行時間は1年間です。そのため、こちらのステートマシンを使用して、1年以上有効化もしくは無効化しておきたい場合は、注意が必要です。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!