[アップデート] EventBridge のイベントパターンでサフィックスや複数のフィールドに対する OR を表現できるようになりました

かゆいところに手が届くようになる系のアップデート
2022.11.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

複数のフィールドに対する OR を表現したいな

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

皆さんは「1つのEventBridgeルールのイベントパターンで、複数のフィールドに対する OR を表現したいな」と思ったことはありますか? 私はあります。

EventBridgeのイベントパターンで定義するフィールドとフィールドはANDで評価されます。

以下のようなイベントパターンを例に考えます。

{
  "detail": {
    "key1": ["value1"],
    "key2": ["value1"],
    "key3": ["value1"]
  }
}

こちらのイベントパターンは以下のような条件になります。

  • detail.key1value1かつ
  • detail.key2value1かつ
  • detail.key3value1

もし、以下のようにORで条件を繋げたい場合は、EventBridgeルールを分割する必要があります。

  • detail.key1value1もしくは
  • detail.key2value1もしくは
  • detail.key3value1

似たようなイベントパターンで同じターゲットに対して処理を行うのであれば、EventBridgeルールの数は減らしたいものです。

そんな複数のフィールドに対するORが、本日のアップデートで表現できるようになりました。

今回のアップデートにより、EventBridge のイベントパターンで以下機能が追加・強化されたようです。

  • サフィックスによるフィルタリング (suffix) の追加
  • 大文字と小文字の区別を無視 (equals-ignore-case) の追加
  • 複数のフィールドに対する OR ($or) の追加
  • 数値 (numeric) でサポートされる範囲を「-1.0e9 - +1.0e9」 から「-5.0e9 - +5.0e9」に強化

また、東京、大阪リージョンとほとんどのリージョンで使えるようになっています。

AWS 公式ドキュメントの EventBridge のドキュメント更新履歴を確認してみます。

Change Description Release Date
Updated content filtering in event patterns. You can now use suffix, equals-ignore-case, and $or filtering options to create event patterns.
Content filtering in Amazon EventBridge event patterns
November 14, 2022

抜粋 : Document History - Amazon EventBridge

数値がサポートされる範囲が強化された以外は言及されていますね。

早速確認してみたので紹介します。

いきなりまとめ

  • EventBridge のイベントパターンで以下機能が追加・強化された
    • サフィックスによるフィルタリング (suffix) の追加
    • 大文字と小文字の区別を無視 (equals-ignore-case) の追加
    • 複数のフィールドに対する OR ($or) の追加
    • 数値 (numeric) でサポートされる範囲を「-1.0e9 - +1.0e9」 から「-5.0e9 - +5.0e9」に強化
  • 2022/11/16現在、サフィックスとプレフィックスを AND で評価することはできない

各アップデートの詳細

サフィックスによるフィルタリング (suffix) の追加

各アップデートの詳細について確認します。

まず、「サフィックスによるフィルタリング (suffix) の追加」です。

今まで、プレフィックスによるフィルタリング(prefix)はありましたが、サフィックスによるフィルタリングはありませんでした。

これにより例えば、S3バケットに特定の拡張子のファイル(オブジェクト)が追加されたときに、EventBridgeでトリガーさせるということが簡単に実装できます。

今までは実装しようとする場合、拡張子ごとにプレフィックスを分けて行う必要があったかと思います。今回のアップデートにより、同じプレフィックスに複数の拡張子が混ざっている時も簡単に対応できます。

実際にやってみましょう。

適当なS3バケットを作成します。

その後、バケットに対するイベントをEventBridgeに送信するように設定変更をします。

Amazon EventBridge編集をクリックします。

このバケット内のすべてのイベントについて Amazon EventBridge に通知を送信するを編集

オンに変更して変更の保存をクリックします。

Amazon EventBridge の編集

このバケット内のすべてのイベントについて Amazon EventBridge に通知を送信するオンになったことを確認します。

EventBridgeに通知するよう変更

続いてEventBridgeルールを作成します。

以下のように、追加されたオブジェクトの末尾が.pngである場合というイベントパターンを用意します。

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "object": {
      "key": [{
        "suffix": ".png"
      }]
    }
  }
}

こちらのイベントパターンにマッチした場合に、CloudWatch Logsに出力するようにEventBridgeルールを作成します。

EventBridgeルールの作成

それでは、S3バケットに画像ファイルをアップロードします。アップロードするのは以下の2つです。

  • のんピ.jpg のんピ

  • my_nintendo_switch_history_most_played_games.png my_nintendo_switch_history_most_played_games

imagesというフォルダ配下にアップロードしました。

バケットにオブジェクトをアップロード

CloudWatch Logsに出力されたログを確認すると、以下の通り.pngのファイルをアップロードした時のイベントのみ記録されていました。

{
    "version": "0",
    "id": "1242694c-d997-0033-8274-ea4275613dbb",
    "detail-type": "Object Created",
    "source": "aws.s3",
    "account": "<AWSアカウントID>",
    "time": "2022-11-15T07:46:22Z",
    "region": "us-east-1",
    "resources": [
        "arn:aws:s3:::eventbridge-test-bucket-non-97"
    ],
    "detail": {
        "version": "0",
        "bucket": {
            "name": "eventbridge-test-bucket-non-97"
        },
        "object": {
            "key": "images/my_nintendo_switch_history_most_played_games.png",
            "size": 769078,
            "etag": "be0996ccceac3d8001431a0337404ea8",
            "sequencer": "00637343CEAD8AA32C"
        },
        "request-id": "QMDCPY4TQNK8WGTG",
        "requester": "<AWSアカウントID>",
        "source-ip-address": "<クライアントのIPアドレス>",
        "reason": "PutObject"
    }
}

確かにサフィックスでフィルタリングされていますね。

なお、プレフィックスとサフィックスを AND で評価することは出来なさそうです。

以下のようにイベントパターンを作成しても、プレフィックスとサフィックスは OR で評価されるため、「プレフィックスがimages/」または「サフィックスが.png」という条件になります。

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "object": {
      "key": [{
        "prefix": "images/"
      }, {
        "suffix": ".png"
      }]
    }
  }
}

「〜以外」を表すanything-butで表現しようとしてみます。ベン図で表すと以下のようになります。

イベントパターンのベン図

イベントパターンで表現しようとすると以下のようになります。

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "object": {
      "key": [{
        "anything-but": [{
          "anything-but": {
            "prefix": "images/"
          }
        }, {
          "anything-but": {
            "suffix": ".png"
          }
        }]
      }]
    }
  }
}

こちらのイベントパターンでEventBridgeルールを保存しようとするとEvent pattern is not valid. Reason: Inside anything but list, start|null|boolean is not supported.と怒られました。

AWS公式ドキュメントを改めて見ると、anything-butのプレフィックスのリストは動作しないようです。

Anything-but マッチングは、リストではなく 1 つのプレフィクスでのみ機能します。

Amazon EventBridge イベントパターンでのコンテンツのフィルタリング - Amazon EventBridge

また、そもそもsuffixanything-butに対応していないようです。以下のイベントパターンでEventBridgeルールを保存しようとするとEvent pattern is not valid. Reason: Unsupported anything-but pattern: suffix.と怒られました。

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "object": {
      "key": [{
        "anything-but": {
          "prefix": "images/"
        }
      }, {
        "anything-but": {
          "suffix": ".png"
        }
      }]
    }
  }
}

大文字と小文字の区別を無視 (equals-ignore-case) の追加

次に、「大文字と小文字の区別を無視 (equals-ignore-case) の追加」です。

こちらはその名の通り、大文字と小文字を区別せずにフィルタリングします。

試しに、先ほど作成したEventBridgeルールのイベントパターンを以下のようなイベントパターンに変更します。

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "object": {
      "key": [{
        "equals-ignore-case": "images/MY_NINTENDO_SWITCH_HISTORY_MOST_PLAYED_GAMES.png"
      }]
    }
  }
}

ちなみに、以下のようにsuffixequals-ignore-caseをネストすることはできませんでした。保存する際にEvent pattern is not valid.とエラーになりました。

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "object": {
      "key": [{
        "suffix": {
          "equals-ignore-case": ".png"
        }
      }]
    }
  }
}
{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "object": {
      "key": [{
        "equals-ignore-case": {
          "suffix": ".png"
        }
      }]
    }
  }
}

この状態でmy_nintendo_switch_history_most_played_games.pngimagesフォルダにアップロードします。

CloudWatch Logsに出力されたログを確認すると、以下の通りイベントが記録されていました。

{
    "version": "0",
    "id": "507c73c0-30dd-8338-48ee-43e3a0d01f7f",
    "detail-type": "Object Created",
    "source": "aws.s3",
    "account": "<AWSアカウントID>",
    "time": "2022-11-15T08:16:44Z",
    "region": "us-east-1",
    "resources": [
        "arn:aws:s3:::eventbridge-test-bucket-non-97"
    ],
    "detail": {
        "version": "0",
        "bucket": {
            "name": "eventbridge-test-bucket-non-97"
        },
        "object": {
            "key": "images/my_nintendo_switch_history_most_played_games.png",
            "size": 769078,
            "etag": "be0996ccceac3d8001431a0337404ea8",
            "sequencer": "0063734AECA35899BF"
        },
        "request-id": "T32HXC427PCRA2M0",
        "requester": "<AWSアカウントID>",
        "source-ip-address": "<クライアントのIPアドレス>",
        "reason": "PutObject"
    }
}

複数のフィールドに対する OR ($or) の追加

次に、「複数のフィールドに対する OR ($or) の追加」です。

その名の通り、複数のフィールドに対して OR で評価します。

以下のイベントパターンの場合は、次のいずれかの条件にマッチした場合にトリガーされます。

  • detail.c-countが 0 より大きく 5 以下
  • detail.d-countが 10 未満
  • detail.x-limitが 3.018e2 と等しい
{
  "detail": {
    "$or": [
      { "c-count": [ { "numeric": [ ">", 0, "<=", 5 ] } ] },
      { "d-count": [ { "numeric": [ "<", 10 ] } ] },
      { "x-limit": [ { "numeric": [ "=", 3.018e2 ] } ] }
    ]
  }
}

注意点は$orで1,000以上を超えるルールの組み合わせが発生するとエラーになるという点です。AWS公式ドキュメントには以下のように記載されています。

APIs that accept an event pattern (such as PutRule, CreateArchive, UpdateArchive, and TestEventPattern) will throw an InvalidEventPatternException if the use of $or results in over 1000 rule combinations.

To determine the number of rule combinations in an event pattern, multiply the total number of arguments from each $or array in the event pattern. For example, the above pattern contains a single $or array with three arguments, so the total number of rule combinations is also three. If you added another $or array with two arguments, the total rule combinations would then be six.

Content filtering in Amazon EventBridge event patterns - Amazon EventBridge

(以下機械翻訳結果)

イベント パターンを受け付ける API (PutRule、CreateArchive、UpdateArchive、および TestEventPattern など) は、$or の使用によって 1000 を超えるルールの組み合わせが発生すると、InvalidEventPatternException をスローします。

イベント・パターン内のルールの組み合わせの数を決定するには、イベント・パターン内の各 $or 配列の引数の合計数を掛け算します。たとえば、上記のパターンには 3 つの引数を持つ 1 つの $or 配列が含まれているため、ルールの組み合わせの総数も 3 となります。もし、2つの引数を持つ別の$or配列を追加した場合、ルールの組み合わせは合計で6つになります。

以下のイベントパターンは$orの配列が3つあるため、ルールの組み合わせの数は3 × 1 = 3です。

{
  "detail": {
    "$or": [
      { "c-count": [ { "numeric": [ ">", 0, "<=", 5 ] } ] },
      { "d-count": [ { "numeric": [ "<", 10 ] } ] },
      { "x-limit": [ { "numeric": [ "=", 3.018e2 ] } ] }
    ]
  }
}

以下のイベントパターンは$orを3回ネストしているため、ルールの組み合わせの数は5 × 10 × 10 = 500です。

長いので折りたたんでいます
{
  "$or": [
    {
      "detail": {
        "$or": [
          {
            "version": [
              "0"
            ]
          },
          {
            "a": [
              "1"
            ]
          },
          {
            "b": [
              "1"
            ]
          },
          {
            "c": [
              "1"
            ]
          },
          {
            "d": [
              "1"
            ]
          },
          {
            "e": [
              "1"
            ]
          },
          {
            "f": [
              "1"
            ]
          },
          {
            "g": [
              "1"
            ]
          },
          {
            "h": [
              "1"
            ]
          },
          {
            "i": [
              "1"
            ]
          },
          {
            "object": {
              "$or": [
                {
                  "key": [
                    "example-key"
                  ]
                },
                {
                  "a": [
                    "1"
                  ]
                },
                {
                  "b": [
                    "1"
                  ]
                },
                {
                  "c": [
                    "1"
                  ]
                },
                {
                  "d": [
                    "1"
                  ]
                },
                {
                  "e": [
                    "1"
                  ]
                },
                {
                  "f": [
                    "1"
                  ]
                },
                {
                  "g": [
                    "1"
                  ]
                },
                {
                  "h": [
                    "1"
                  ]
                },
                {
                  "i": [
                    "1"
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    {
      "detail": {
        "$or": [
          {
            "version": [
              "0"
            ]
          },
          {
            "a": [
              "1"
            ]
          },
          {
            "b": [
              "1"
            ]
          },
          {
            "c": [
              "1"
            ]
          },
          {
            "d": [
              "1"
            ]
          },
          {
            "e": [
              "1"
            ]
          },
          {
            "f": [
              "1"
            ]
          },
          {
            "g": [
              "1"
            ]
          },
          {
            "h": [
              "1"
            ]
          },
          {
            "i": [
              "1"
            ]
          },
          {
            "object": {
              "$or": [
                {
                  "key": [
                    "example-key"
                  ]
                },
                {
                  "a": [
                    "1"
                  ]
                },
                {
                  "b": [
                    "1"
                  ]
                },
                {
                  "c": [
                    "1"
                  ]
                },
                {
                  "d": [
                    "1"
                  ]
                },
                {
                  "e": [
                    "1"
                  ]
                },
                {
                  "f": [
                    "1"
                  ]
                },
                {
                  "g": [
                    "1"
                  ]
                },
                {
                  "h": [
                    "1"
                  ]
                },
                {
                  "i": [
                    "1"
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    {
      "detail": {
        "$or": [
          {
            "version": [
              "0"
            ]
          },
          {
            "a": [
              "1"
            ]
          },
          {
            "b": [
              "1"
            ]
          },
          {
            "c": [
              "1"
            ]
          },
          {
            "d": [
              "1"
            ]
          },
          {
            "e": [
              "1"
            ]
          },
          {
            "f": [
              "1"
            ]
          },
          {
            "g": [
              "1"
            ]
          },
          {
            "h": [
              "1"
            ]
          },
          {
            "i": [
              "1"
            ]
          },
          {
            "object": {
              "$or": [
                {
                  "key": [
                    "example-key"
                  ]
                },
                {
                  "a": [
                    "1"
                  ]
                },
                {
                  "b": [
                    "1"
                  ]
                },
                {
                  "c": [
                    "1"
                  ]
                },
                {
                  "d": [
                    "1"
                  ]
                },
                {
                  "e": [
                    "1"
                  ]
                },
                {
                  "f": [
                    "1"
                  ]
                },
                {
                  "g": [
                    "1"
                  ]
                },
                {
                  "h": [
                    "1"
                  ]
                },
                {
                  "i": [
                    "1"
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    {
      "detail": {
        "$or": [
          {
            "version": [
              "0"
            ]
          },
          {
            "a": [
              "1"
            ]
          },
          {
            "b": [
              "1"
            ]
          },
          {
            "c": [
              "1"
            ]
          },
          {
            "d": [
              "1"
            ]
          },
          {
            "e": [
              "1"
            ]
          },
          {
            "f": [
              "1"
            ]
          },
          {
            "g": [
              "1"
            ]
          },
          {
            "h": [
              "1"
            ]
          },
          {
            "i": [
              "1"
            ]
          },
          {
            "object": {
              "$or": [
                {
                  "key": [
                    "example-key"
                  ]
                },
                {
                  "a": [
                    "1"
                  ]
                },
                {
                  "b": [
                    "1"
                  ]
                },
                {
                  "c": [
                    "1"
                  ]
                },
                {
                  "d": [
                    "1"
                  ]
                },
                {
                  "e": [
                    "1"
                  ]
                },
                {
                  "f": [
                    "1"
                  ]
                },
                {
                  "g": [
                    "1"
                  ]
                },
                {
                  "h": [
                    "1"
                  ]
                },
                {
                  "i": [
                    "1"
                  ]
                }
              ]
            }
          }
        ]
      }
    }
  ]
}

こちらのイベントパターンでもEventBridgeルールは保存できました。

どちらかというと、こちらの制限よりもイベントパターンの最大文字数2,048文字の方に先に引っかかりそうな気がします。

こちらも試してみます。

以下のいずれかの条件にマッチした場合というイベントパターンを定義します。

  • 末尾が.pngのオブジェクトが作成された
  • 末尾が.jpgのオブジェクトが削除された

イベントパターンは以下の通りです。

{
  "source": ["aws.s3"],
  "$or": [{
      "detail-type": ["Object Created"],
      "detail": {
        "object": {
          "key": [{
            "suffix": ".png"
          }]
        }
      }
    },
    {
      "detail-type": ["Object Deleted"],
      "detail": {
        "object": {
          "key": [{
            "suffix": ".jpg"
          }]
        }
      }
    }
  ]
}

まず、my_nintendo_switch_history_most_played_games.pngを再度S3バケットにアップロードします。

CloudWatch Logsに出力されたログを確認すると、以下の通りイベントが記録されていました。

{
    "version": "0",
    "id": "df57686d-5b34-4495-5548-a3acbd8947ad",
    "detail-type": "Object Created",
    "source": "aws.s3",
    "account": "<AWSアカウントID>",
    "time": "2022-11-15T10:31:13Z",
    "region": "us-east-1",
    "resources": [
        "arn:aws:s3:::eventbridge-test-bucket-non-97"
    ],
    "detail": {
        "version": "0",
        "bucket": {
            "name": "eventbridge-test-bucket-non-97"
        },
        "object": {
            "key": "images/my_nintendo_switch_history_most_played_games.png",
            "size": 769078,
            "etag": "be0996ccceac3d8001431a0337404ea8",
            "sequencer": "0063736A7173801706"
        },
        "request-id": "C50DX737K2RAXERY",
        "requester": "<AWSアカウントID>",
        "source-ip-address": "<クライアントのIPアドレス>",
        "reason": "PutObject"
    }
}

続いて、のんピ.jpgをS3バケット上から削除します。

CloudWatch Logsに出力されたログを確認すると、以下の通りイベントが記録されていました。

{
    "version": "0",
    "id": "25301900-81a7-e6ac-e3fb-da39d66a34df",
    "detail-type": "Object Deleted",
    "source": "aws.s3",
    "account": "<AWSアカウントID>",
    "time": "2022-11-15T10:35:11Z",
    "region": "us-east-1",
    "resources": [
        "arn:aws:s3:::eventbridge-test-bucket-non-97"
    ],
    "detail": {
        "version": "0",
        "bucket": {
            "name": "eventbridge-test-bucket-non-97"
        },
        "object": {
            "key": "images/のんピ.jpg",
            "sequencer": "0063736B5F7B5B1359"
        },
        "request-id": "0AEEYRB87PFV1K8K",
        "requester": "<AWSアカウントID>",
        "source-ip-address": "<クライアントのIPアドレス>",
        "reason": "DeleteObject",
        "deletion-type": "Permanently Deleted"
    }
}

数値 (numeric) でサポートされる範囲を「-1.0e9 - +1.0e9」 から「-5.0e9 - +5.0e9」に強化

最後に、「数値 (numeric) でサポートされる範囲を『-1.0e9 - +1.0e9』 から『-5.0e9 - +5.0e9』に強化」です。

カスタムイベントなどで大きな値を扱う場合は従来の「-1.0e9 - +1.0e9」では足りないこともあったかと思います。今回のアップデートによりEventBridgeが扱える数値の範囲が「-5.0e9 - +5.0e9」に強化されました。これにより50億までの数値はイベントパターンで制御することができます。

こちらも試してみます。

Step FunctionsからEventBridgeにカスタムイベントを発行して対応します。

5.0e9までサポートしているとのことなので、Step Functionsで5000000000(50億)という数値をカスタムイベントとして発行します。

{
  "Comment": "A description of my state machine",
  "StartAt": "EventBridge PutEvents",
  "States": {
    "EventBridge PutEvents": {
      "Type": "Task",
      "Resource": "arn:aws:states:::events:putEvents",
      "Parameters": {
        "Entries": [
          {
            "Detail": {
              "value": 5000000000
            },
            "DetailType": "MyDetailType",
            "EventBusName": "default",
            "Source": "MySource"
          }
        ]
      },
      "End": true
    }
  }
}

イベントパターンは以下のように「3.0e2(3000000000)以上である場合」というように定義します。

{
  "detail-type": ["MyDetailType"],
  "detail": {
    "value": [{
      "numeric": [">", 3.0e2]
    }]
  }
}

イベントパターン変更後、ステートマシンを実行します。

CloudWatch Logsに出力されたログを確認すると、以下の通りStep Functionsから発行したカスタムイベント記録されていました。

{
    "version": "0",
    "id": "4fbe21b6-5963-214a-9d69-1004e9c5f31f",
    "detail-type": "MyDetailType",
    "source": "MySource",
    "account": "<AWSアカウントID>",
    "time": "2022-11-15T09:51:20Z",
    "region": "us-east-1",
    "resources": [
        "arn:aws:states:us-east-1:<AWSアカウントID>:stateMachine:TestStateMachine",
        "arn:aws:states:us-east-1:<AWSアカウントID>:execution:TestStateMachine:348b9142-b338-02b8-4555-0744af1fe54c"
    ],
    "detail": {
        "value": 5000000000
    }
}

本当に5.0e9が限界か確認するために、発行するカスタムイベントを5000000001に変更してみました。

{
  "Comment": "A description of my state machine",
  "StartAt": "EventBridge PutEvents",
  "States": {
    "EventBridge PutEvents": {
      "Type": "Task",
      "Resource": "arn:aws:states:::events:putEvents",
      "Parameters": {
        "Entries": [
          {
            "Detail": {
              "value": 5000000001
            },
            "DetailType": "MyDetailType",
            "EventBusName": "default",
            "Source": "MySource"
          }
        ]
      },
      "End": true
    }
  }
}

変更後にステートマシンを実行したところ、CloudWatch Logsにはログが記録されませんでした。確かに限界は5.0e9のようです。

かゆいところに手が届くようになる系のアップデート

EventBridge のイベントパターンでサフィックスや複数のフィールドに対する OR を表現できるようになったアップデートを紹介しました。

サフィックスによるフィルタリングなんかは待ち望んでいた人が多いのではないでしょうか。

こういった、かゆいところに手が届くようになる系のアップデートはありがたいですね。

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

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