Upgrade to Pro — share decks privately, control downloads, hide ads and more …

EventBridge に「合流」はない ― サーバーレスのワークフローを育てるということ /...

EventBridge に「合流」はない ― サーバーレスのワークフローを育てるということ / No Join in EventBridge

日次ETLを1本の Step Functions から2本に分割したら、後続の起動条件が「先行ワークフローの完了」かつ「上流バッチの完了」という AND になりました。EventBridge には複数のイベントを合流させる機能がありません。SQS でも、AND の成立を判定する部分は自分で作ることになります。

このセッションでは「合流をどこに置くか」を、起動条件の入れ替え / 実行内でのポーリング / Parallel / タスクトークン / 外部状態ストアの5案で、それぞれがどう壊れるかとあわせて比較しました。あわせて、後続の起動を先行ワークフローの末尾に書いたときに、処理が全て成功していてもワークフロー全体が失敗扱いになる、という状態表現の壊れ方も扱っています。

ServerlessDays Tokyo 2025 で話した「アーキテクチャは育てるもの」「適応度関数で測る」の続きです。本番のワークフローに手を入れる段になって、測っていたのは処理の成否だけで、出力の鮮度ではなかったと気づいた話でもあります。

- ServerlessDays Tokyo 2026 / 2026.09.19 / Track C
- 登壇者: 志水友輔 (@shimi023)
- イベントページ: https://tokyo.serverlessdays.io/
- 前回(ServerlessDays Tokyo 2025): https://speakerdeck.com/yusukeshimizu/wan-bi-womu-zhi-sanai-sabaresujin-hua-lun-cdkdeyu-terubian-hua-niqiang-iakitekutiya

Avatar for Yusuke Shimizu

Yusuke Shimizu

September 18, 2026

More Decks by Yusuke Shimizu

Other Decks in Technology

Transcript

  1. NRIネットコム株式会社 / Cloud Architect 志水 友輔(しみず ゆうすけ) アーキテクト・AI活用推進・人材育成・技術広報 Japan AWS

    Ambassador(2023-2026) AWS CDK / Amazon Bedrock AgentCore / カメラ / つけ麺 最近、子どもに 「パパのこと、ちょっとだけ大好き」と言われます Blog: #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 3
  2. 前回の話 アーキテクチャは、育てるもの 2025年 ServerlessDays Tokyo での志水の登壇「完璧を目指さない サーバーレス進化論」― 進化的アーキテクチャの輪 変化が 来る

    ← 今回はここから 今回は、その2周目。 新しい変化が来た。 適応度 前回 特性を 確かめる 小さく 変える 技術の変化 ― AWS Lambda 15分の壁 今回 締切の前倒し ― 1本のままでは間に合わない #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 4
  3. 目次 1. 発端 なぜ、1本のワークフローを2本に分けたのか 2. 合流はない 分けたら、何が足りなくなったのか 3. 合流を、どこに置くか 5つの置き場所を、何で比べて選んだか

    4. 成否がずれる 起動のしかたで、何が変わるのか 5. 締切を、外から確かめる 分けたあと、締切をどう確かめるか #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 5
  4. 1. 発端 Aのデータだけ先に出すための、2本への分割 Aのデータ(他チームのバッチは使わない) Bのデータ(他チームのバッチを使う) 他チームのバッチの終了 他チームのバッチ Bのデータの材料 元の形(1本) 1本のまま早く始める

    利用者Aの締切 Aの締切に間に合わない Aのデータ Aのデータ Bのデータ Bのデータ Bのデータが、古いままになる Bのワークフロー 締切はAと別。他チームの後に作る Aのワークフロー(他チームを待たない) 2本に分ける ↑ Aと他チームの両方を待つ 時間 → #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 7
  5. 1. 発端 Aだけでも、他チームのバッチだけでも足りない Aの完了だけで起動すると(他チームが遅れた日) 他チームの終了 他チームのバッチ Aのワークフロー Aのデータを作る Bのデータを作る Bのワークフロー

    他チームの完了だけで起動すると(いつもの日) 他チームより先。Bのデータが古い 他チームの終了 他チームのバッチ Aのワークフロー Bのワークフロー Aのデータを作る Bのデータを作る Aと同時に走ってしまう 作業領域を共有しているので壊れる だからBは、Aの完了 と 他チームのバッチの完了 の両方を待つ ― AND #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 8
  6. 2. 合流はない 2つ並べると、2回起動する Amazon EventBridge AWS Step Functions Aの完了 Aを見るルール

    Bが起動 Aの完了で発火 Aの完了だけを見て Amazon EventBridge Rule AWS Step Functions → Bが 2回 起動する しかも、どちらの起動も AND を満たしていない 他チーム のバッチ 他チームのバッチの完了 他チームを見るルール Bが起動 他チームの完了で発火 他チームの完了だけを見て Amazon EventBridge Rule AWS Step Functions ルールは1イベントごとに独立して発火する。待ち合わせの概念がない。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 11
  7. 2. 合流はない Amazon SQS でも同じ ― 相関IDだけでは足りない 足りない ― 結局こちらで作る

    Aの完了 相関ID = 同じ日 到着状態を 覚えておく場所 Message 他チームの完了 Amazon SQS 相関ID = 同じ日 相関IDは、自分で入れて自分で読む値 Message Amazon SQS はその意味を解釈しない AWS Step Functions 揃ったと 判定する処理 B ※ FIFO の MessageGroupId(順序)とは違う 相関IDで「同じ組」は分かる。でも「揃った」は、誰も判定してくれない。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 12
  8. 2. 合流はない EIP には Aggregator という名前がある Enterprise Integration Patterns(Gregor Hohpe,

    Bobby Woolf, 2003)― システム連携のパターン集 メッセージ 組:同じ日 Aggregator 1通目 ✓ 1通にまとめて出す 2通目 まだ メッセージ 揃うまで覚えておく 組:同じ日 01 Correlation 02 どれとどれが、同じ組か Completeness Condition いつ「揃った」とみなすか 03 Aggregation Algorithm どうまとめて1つにするか EIP は Aggregator を "a stateful filter"(状態を持つフィルタ)と定義している。 #serverlessjp 出典:Enterprise Integration Patterns 公式サイト「Aggregator」(Gregor Hohpe, Bobby Woolf) https://www.enterpriseintegrationpatterns.com/patterns/messaging/Aggregator.html Copyright(C) NRI Netcom, Ltd. All rights reserved. 13
  9. 2. 合流はない 機能が足りないのではなく、部品の種類が違う Amazon EventBridge / Amazon SQS Aggregator 1件ずつ、届ける

    組ごとに、揃うまで覚えておく イベント 届け先 届いたもの Amazon Amazon SQS EventBridge 1通目 ✓ 2通目 まだ Amazon SQS はメッセージを溜める。 「どれが来て、どれがまだか」=組の状態を持つ。 Amazon EventBridge のルールは1件ずつ判定する。 EIP の定義も "a stateful filter"。 揃ったら出す どちらも「どれが来て、どれがまだか」は見ない。 だから機能追加を待っても、合流は来ない。「組の状態」を覚える場所は自分で置く。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 14
  10. 2. 合流はない 「揃った」の決め方には、5種類ある EIP が挙げる Completeness Condition の戦略 Wait for

    All 全部揃うまで待つ(来なければ期限でエラーに) Time Out 一定時間待って、そこで判断する First Best 最初の1つが来たら、残りは無視する Time Out with Override 特に良い返事が来たら早めに打ち切る External Event 外部の出来事で締める ← 今回はこれ #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 15
  11. 2. 合流はない 当てはめると、要るのは3つのうち2つ 2つのデータを1つにしたいのではない。揃ったら、次を動かしたいだけ。 Aの完了 組:同じ日 Aggregator A✓ Bを起動するだけ (まとめるものはない)

    他チーム まだ 他チームのバッチの完了 揃うまで覚えておく 組:同じ日 01 Correlation 今回:同じ日の組 02 Completeness Condition 今回:両方来たら(Wait for All) 03 Aggregation Algorithm 今回:要らない 欲しかったのは集約ではなく、合流だった。要るのは「揃ったかを覚えておく場所」だけ。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 16
  12. 3. 合流を、どこに置くか 合流の置き場所は、5つあった ① ② ③ ④ ⑤ 起動条件の入れ替え タスクトークン

    Parallel 外部状態ストア 実行内でポーリング 他チームを起点にする 押してもらう そもそも分けない 外で揃えてから起動する Bの中で待つ 採用 中央の丸が合流点。何を置くかだけが違う。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 19
  13. 3. 合流を、どこに置くか ① 起点を替えても、待ちは消えない Aの完了を確認する手段が重く、 しかも毎日、Aを待つことになる 当日の実行を ListExecutions で特定して状態を判定する必要がある 実績では、他チームのバッチよりAのほうが後に終わる

    他チームのバッチを起点にすると、起動してからAが終わるまで、毎日待つことになる 増える部品 普段の待ち なし(当日の実行の特定が複雑) 毎日待つ #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 21
  14. 3. 合流を、どこに置くか ② 押してもらうにも、部品が要る トークンの保管先と AWS Lambda が要り、 ④ と同じくらいの部品数になる

    トークンは、待つ側が先に止まっていないと返せない 知らせが先に来ると空振りして、そのまま止まり続ける どちらが先に来ても合うように、到着を覚えておく場所が要る 増える部品 普段の待ち トークンの保管先+AWS Lambda なし #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 23
  15. 3. 合流を、どこに置くか ③ Parallel そもそも分けない。 親のステートマシンで覆って、並列に走らせる。 Aと他チームのバッチを1つのワークフローに包む 合流は AWS Step

    Functions が持っている 両方を自分で動かせるなら、問題自体が消える #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 24
  16. 3. 合流を、どこに置くか ③ 他チームのバッチが相手だと、強みが使えない 合流を AWS Step Functions に任せられるのは、 両方を自分で起動できるときだけ

    他チームのバッチをいつ起動するかは、向こうが決める。権限の問題ではない だからブランチにできない。入れられるのは、他チームの完了を待つ処理だけ AとBが1つの実行に入る。Bが失敗すると、Aのデータを出せていても全体が FAILED 増える部品 普段の待ち 親のステートマシン なし #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 25
  17. 3. 合流を、どこに置くか ④ 合流のためだけに、運用対象が1つ増える 合流のためだけに増える部品 1 A✓ AWS Step Functions

    片方が来ないと、気づかず止まる フラグが半分埋まったまま残る 他チーム まだ 1 揃ったら起動 変更を通知 Aの完了 2 2 同時に届くと、2回起動する 条件付き書き込みを書き忘れた場合 Amazon DynamoDB 他チーム のバッチ 他チームの完了 AWS Lambda AWS Step Functions 揃ったか判定 B 運用するものが増える テーブル IaC TTL 3 権限 増える部品 普段の待ち Amazon DynamoDB+AWS Lambda なし 監視 3 日跨ぎのリセットが要る TTL を切れば溜まり、短いと調べられない #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 28
  18. 3. 合流を、どこに置くか ⑤ 実行内でポーリング Aの完了でBを起動し、 Bの冒頭で他チームのバッチの完了を見に行く。 Aの完了 → Amazon EventBridge

    ルールで起動 他チームは終わったら Amazon S3 にマーカーを置く Bの冒頭で Wait + Choice で待つ #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 29
  19. 3. 合流を、どこに置くか なぜ、一番地味な案を採ったか 実績を見ると 待ちは、ほぼゼロ 待ちがほぼないなら、利点だけが残る 既存の完了待ちと同型で書ける 新しい種類の部品を持ち込まない 監視対象・障害点・運用手順が増えない Aのほうが、他チームのバッチより後に終わる。

    状態が残るので、翌朝確認できる Bが起動する時点で、他チームはもう終わっている。 待つ設計を選べたのは、普段は待たないから。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 30
  20. 3. 合流を、どこに置くか ⑤ 遅れた日ほど、高くつく 通常時ゼロで済んでいる待ちが、 遅れた日だけ跳ね上がる Standard は状態遷移ごとの課金。待つほど遷移が増える ステートマシンのタイムアウトに、待っている時間も含まれる 実行が長時間

    RUNNING のまま ― 正常に待っているのか、詰まっているのか区別できない 増える部品 普段の待ち なし ほぼゼロ(遅れた日だけ増える) #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 31
  21. 3. 合流を、どこに置くか 5案を、まとめて比べる 合流の置き場所 増える部品 普段の待ち ① 起動条件の入れ替え なし(当日の実行の特定が複雑) 毎日待つ

    ② タスクトークン トークンの保管先+AWS Lambda なし ③ Parallel 親のステートマシン なし ④ 外部状態ストア Amazon DynamoDB+AWS Lambda なし ⑤ 実行内でポーリング なし ほぼゼロ ← 採用 部品を増やさず、普段は待たない。両方を満たすのは⑤だけ。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 32
  22. 4. 成否がずれる 外で拾うか、中に書くか 外で拾う(採用) Aの定義に、Bは出てこない Aのワークフロー SUCCEEDED 処理1 B 処理2

    Amazon EventBridge Rule 中に書く 最後のステップで、Bを起動 AWS Step Functions Aのワークフロー 処理1 処理2 StartExecution B AWS Step Functions 違いは、Bの起動が「Aの一部」になるかどうか。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 35
  23. 4. 成否がずれる 起動の失敗が、Aの失敗になる Aのワークフロー 処理1 ✓ 処理2 ✓ ↓ このステップはAの一部なので

    StartExecution ✗ Bのワークフロー Bの起動だけが失敗しても、 データ処理は成功しているのに画面上は失敗。 Aのワークフロー全体が FAILED ③ Parallel でも、親の単位で同じことが起きる。 監視の要件に合わず、設計の時点で外した 「処理の成否」と「ワークフローの成否」が、ずれる。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 36
  24. 5. 締切を、外から確かめる 5案とも、来なかったときの期限を決めていない EIP も Wait for All には「来なければ、期限でエラーにすべき」と書いている ①

    起動条件の入れ替え Wait for All 期限:なし ② タスクトークン Wait for All 期限:なし ③ Parallel Wait for All 期限:なし ④ 外部状態ストア Wait for All 期限:なし ⑤ 実行内でポーリング Wait for All 期限:なし 「何時までに来なければ異常にする」は、どの案でも自分で書く必要がある。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 39
  25. 5. 締切を、外から確かめる 合流を正しく作ると、失敗は「止まる」形で出る 合流で待つ(採用) 時刻で決め打ちしていたら 黙って 止まる 黙って 進む 他チームが来なければ、Bは待つ。

    遅れた日も、Bは動く。 動いたなら、必ず揃ったデータで作る。 古い入力のまま、成功する。 古いまま成功は、構造で防げている。 当時の検討資料にも「サイレント障害」とある。 残る問題は1つ。止まったことに、中からはアラートが出ない。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 40
  26. 5. 締切を、外から確かめる 冒頭の輪の、3つ目の点に戻る 「特性を確かめる」― 前回これを適応度関数と呼んだ。この案件では、締切がそれにあたる。 実行時間で確かめられる 実行時間では確かめられない Aのデータが Bのデータが 締切に間に合うか

    締切に間に合うか 実行時間を、締切から逆算したしきい値で見る 起動されない日も、待ち続ける日も、数字が出ない 超えたら構成を見直す合図 ― 今回の分割がこれ 分けたことで生まれた壊れ方 適応度関数 = 守りたい特性に、客観的な基準をつけて確かめる仕組み。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 42
  27. 5. 締切を、外から確かめる では、どう確かめるか 正直に言うと、Bの締切を確かめる方法は、まだ入れていない。 何で確かめる 拾えるもの 今 実行時間 × 締切から逆算したしきい値

    Aの締切 Bの締切も、最後まで動いた日なら これから ① Bの中に打ち切り時刻を入れて Fail (時刻はBの締切から逆算) 待ち続ける日 これから ② Bの締切の時刻に、外から 今日分の出力を見る 構成を変えたときの 起動漏れ 皆さんのチームでは、ここをどう確かめていますか。 #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 44
  28. 5. 締切を、外から確かめる 確かめ方も、分けた形に合わせる 冒頭の輪を、配置を変えずにもう一度。 変化が 来る 構成を育てたなら、 測る次元も育てる。 適応度 特性を

    確かめる 小さく 変える 前回の3つ目の要素は「多重な次元」。 分けて生まれた壊れ方を、拾えていなかった。 ↑ ここに穴があった #serverlessjp Copyright(C) NRI Netcom, Ltd. All rights reserved. 45