Step Functionsを採用することで柔軟性・堅牢性・拡張性を持った通知基盤を構築した事例
MOSH株式会社 / doriven
メンバー / バックエンドエンジニア / 従業員規模: 51名〜100名 / エンジニア組織: 11名〜50名
| ツールの利用開始時期 | 事業形態 |
|---|---|
| 2025年8月 | B to C |
| ツールの利用開始時期 | 2025年8月 |
|---|---|
| 事業形態 | B to C |
アーキテクチャ

アーキテクチャの意図・工夫
Step Functions定義の工夫
Standard ModeとExpress Modeの使い分け
- 基本となるワークフローはStandard Modeで実行
- 一部のMap State内の通知処理: Express Mode(高スループット6,000/秒)を活用しquota・料金面で優位な点がある一方でRedrive不可能な点やAtLeastOnceな特性があることを留意する必要があるので使いどころは難しい
リトライ設定の最適化
- ErrorEqualsに
States.TaskFailedを指定し、全エラーを一律リトライするようにした - ExponentialBackoffアルゴリズムでリトライ間隔を調整
- MaxDelaySecondsで過度な遅延を防止した
- 総リトライ時間を短く設定(ETL: 2分、通知: 3分)し、早期失敗検知
- ErrorEqualsに
HTTP Invokeタスクの活用
- HTTP Invokeを使うことでExpress Modeでも同期的にパラメータの受け渡しが可能になる
Parallel Stateによる拡張性
- 通知方法ごとにブランチを分離
- 新しい通知方法の追加が既存フローに影響しない
- 各ブランチの失敗が他のブランチに波及しない
DynamoDBによる冪等性の担保
通知の重複送信を確実に防ぐため、DynamoDBを用いた状態管理型の冪等性制御を実装しました。
課題背景
- 個別の通知処理を行うMap StateがExpress Modeで実行されるため、AtLeastOnce特性により重複通知が行われる可能性がある
- Redrive処理実行時に部分的に送信済みの場合は重複通知が発生する可能性がある
DynamoDB採用理由
技術的優位性
- 条件付き書き込み(Conditional Writes)による確実な排他制御
- 強整合性による競合状態の回避
- TTL機能による自動的なデータクリーンアップ
性能面の優位性
- 単一桁ミリ秒の低レイテンシ
- コネクション管理不要による処理の簡素化
コスト効率性
- オンデマンド課金による使用量に応じた料金
- RDBやElastiCacheと異なり固定コストなし
冪等性制御の仕組み
- 通知送信前にDynamoDBにIDをキーとして 「処理中」状態のレコードを条件付き書き込み
- 既に 「処理済み」または「処理中」の場合は処理をスキップ
- 「処理中」から一定時間経過している場合は再処理を許可
- 通知送信成功時に「完了」、失敗時に「失敗」に状態を更新
この仕組みにより、Redrive実行時や途中で処理が中断した場合でも、重複通知を発生させることなく安全に再実行できるようになりました。
導入の背景・解決したかった問題
導入背景
サービスの概要と通知の重要性
弊社ではオールインワンなクリエイターエコノミーを支援するWebアプリケーションを提供しています。
サービスを作成・販売するクリエイターや、それらを購入・予約するゲストが存在し、システムが両者へメール・LINE・Webアプリ内で購入・予約の発生や決済完了などの通知を行っています。
これらの通知を起点にクリエイターやゲストは行動を開始するので、サービスとしては非常に重要であり、通知が届かない = ユーザ体験の悪化を招くことになります。
ツール導入前の課題
急成長のため事業規模が急激に拡大しており、マルチプロダクト戦略を取る方向性がありました。
今後増え続けるプロダクトで、メール・LINEやプロダクト内の通知処理を個別に実装するのは成長の足かせになることが見えていました。
また通知は、事業において重要な要素である一方で、既存のシステムにおいて通知が失敗するとリトライが行えず、直接Webページで状況を確認するようにユーザの皆様にお願いをするなど、著しくユーザ体験を損なっていました。
どのような状態を目指していたか
上記を受けて以下の状態を満たせる基盤を構築することになりました。
- 通知の種別が増えることに対応が可能なこと
- 将来的に想定される通知数の進捗状況の管理・完了通知などの機能を追加可能なこと
- 通知を依頼する先(例: LINE Message API)で障害が発生しても後からリトライが可能なこと
- 通知が増えてもスケールし許容範囲内の時間で通知がされること
比較検討したサービス
Step Functions
⭕️Pros
- 処理フローがAWSコンソールで可視化され、全体像の理解が容易なこと
- 柔軟性が高く、処理完了後に新しい処理を挿入しやすい
- Redrive機能により、失敗した処理の再実行が手軽なこと ※ StandardMode限定
- HTTP Invokeタスクで内部APIを直接呼び出せる(Lambdaが不要)
❌️Cons
- StartExecutionのリクエストサイズ1MB制限、Stateの入出力256KB制限があり、サイズを超える場合はS3経由のPayload展開処理が必要
- Standard ModeのStartExecution制限(150/秒)がボトルネックになる可能性
- Express Modeの実行時間制限(5分)
- 学習コストが高い(細かい仕様理解が必要)
Fluent(FluentBit/Fluentd)を利用したファイル駆動のマイクロバッチ
⭕️Pros
- 外部システムへの依存が少ないので可用性が高い
- インスタンスの中で処理が完結するため、高いスケーラビリティを持ち、Quota制限も存在しない(実質、インスタンス性能が制限と等しくなる)
- Step Functionsなどのワークフローエンジンと比較すれば、学習コストが比較的低い
❌️Cons
- ワークフロー全体の処理フローの把握が難しい
- ストリーム処理のため以下の制約がある
- ワークフローが完了したことを検知するには仕組みの構築が必要
- 並列処理の完了を同期的に待つなどは仕組みの構築が必要
Apache Airflow
⭕️Pros
- ワークフローの可視化と管理が可能
- Python DSL(DAG)で柔軟にワークフローを定義できる
- スケジューリング機能が充実
- 大規模なバッチ処理に強い
❌️Cons
- マネージドサービスでない場合はインフラの構築・運用コストが高い
- リアルタイム性に欠ける(主にバッチ処理向け)
- AWSサービスとの統合がStep Functionsほど密ではない
- 小規模なワークフローには過剰な機能
- 通知基盤のようなイベント駆動の処理には向いていない
選定理由
以下の観点からStep Functionsを採用しました。
- 処理フローの可視化: ワークフローが可視化でき、全体像の理解が容易
- 柔軟性: 特定の処理完了後に新しい処理を挿入しやすい
- 例: 全メッセージ送信完了後にステータス更新が容易
- 通知数カウンティング機能の追加が既存フローに影響なく実装可能
- 失敗処理の再実行: Redrive機能により失敗した処理の手軽な再実行が可能
- 将来的な要件への対応: 「通知が届ききっているか」の確認機能など、将来的な要望に対応しやすい
導入の成果
改善したかった課題はどれくらい解決されたか
導入前に設定した目標に対する達成状況:
- 通知の種別が増えることに対応が可能なこと: 達成
- Parallel Stateで通知方法を並列実行する設計により、新しい通知方法の追加が容易に設計した
- これによりメール→LINE→アプリ内通知という段階的に移行が行えた
2.*通知数の進捗状況の管理・完了通知などの機能を追加可能なこと: 達成
- Map State完了後にカウンティングAPIを呼び出す処理を追加する要求に対してADRを記載し対応可能なことが分かっている
通知を依頼する先で障害が発生しても後からリトライが可能なこと: 達成
- Redrive機能により失敗したStep Functions実行を手軽に再実行可能
- これにより2025年10月に発生した北米AWS障害による障害も収束後にリトライを簡単に行うことが出来た実績を残せた
通知が増えてもスケールし許容範囲内の時間で通知がされること: 達成
- 大量の通知が発生した場合でも問題なく稼働することを確認
どのような成果が得られたか
※ 執筆時点で通知基盤への完全な移行が済んでいないため、以下は移行したものだけが対象
- ユーザ体験の向上: 通知失敗時に「Webページでご確認ください」とお願いする必要がなくなった
- 運用負荷の軽減: 処理フローの可視化により障害対応が容易になり、運用チームの負担が減少
- 拡張性の確保: 通知数カウンティング機能など新機能の追加が既存フローに影響なく可能
- マルチプロダクト対応: 通知基盤として複数プロダクトから利用可能な構成を実現
- 開発速度の向上: 各プロダクトで個別に通知処理を実装する必要がなくなり、開発リソースを削減
導入時の苦労・悩み
Step Functions自体がそれなりに複雑でキャッチアップまで時間が掛かる
ステート間のパラメータの受け渡しをどのようにすればいいのか、リトライを行うにはどうすればいいのか、実行モードがStandardとExpressで複数あるがどのような違いがあるか、などなど上げればキリがありません。
Step Functionsは優秀なワークフロー実行基盤である一方で、AWSの特性と合わせつつそれらの特徴を抽出し、我々のユースケースにマッチするのかをキャッチアップするまではPoCも合わせて時間がかかりました。
通常の利用であれば概ね対応可能だと思うので、キャッチアップの苦労がStep Functionsを採用するうえで一番の障壁になりえます。
渡せるパラメータのサイズ制限が厳しい
StartExecutionのリクエストサイズが1MB制限、Stateの入出力が256KB制限を持っているため、通知基盤のように複数の相手に複数のメッセージを送れる機能だと上限を突破してしまいます。
そのためS3を経由したPayload展開処理が全下流処理に必要で、処理の複雑性が上がってしまうことや、依存する外部サービスが増えることによる可用性の低下が懸念でした。
他の選択肢よりも優位な点があることを考慮し、ここは受け入れることにしました。
導入に向けた社内への説明
上長・チームへの説明
プロジェクトメンバーとしてはエンジニアが私を含め2名、テクニカルプロダクトマネージャーが1名の3名構成でした。
通知回りの課題感や、今後のマルチプロダクトは組織も小さく、経営方面にも事前に伝わっていたため、課題感を伝えるところに苦労はありませんでした。
私はプロダクトリードのとして、アーキテクチャの妥当性をFigJamでアーキテクチャ図を複数作成・共有しつつ、事前に大枠での認識合わせを行い、
微細な詰めはADRを書いて、GitHub上で行うというフローで資料を残しつつ、オンライン上で議論を進めていく方法で説明責任を全うしました。
以下に議論した点について記載します。
費用対効果
Step Functionsは$0.025/1,000状態遷移となり、シンプルなワークフローであれば安いです。
1つの通知あたり10Stateを消費すると仮定しても、$1,000の課金に到達するまでに400万通知であり、現状の通知数と今後の通知数の増加を考慮しても許容できる範囲内でした。
(厳密には、後述するExpressModeでは異なる課金体系になりますが、複雑かつ料金も安いため試算からは外しています)
今後のマルチプロダクト戦略・堅牢な通知基盤を構築するためにStep Functionsを採用することは、メリットがあるため必要経費として判断しています。
活用方法
サービスを販売するクリエイター、サービスを購入するゲストという2つのロールに向けて通知基盤を経由してメール・LINE・アプリ内通知を行っています。
- クリエイターからゲストへ連絡があったこと
- クリエイターに問い合わせがあったこと
- クリエイターのサービスの購入・予約が発生したこと 等など
よく使う機能
通知ワークフローにおいて以下を行っています。
- マネジメントコンソール上での可視化による、処理の理解促進
- 通知処理の実行
- 失敗した通知処理の再試行(Redrive)
ツールの良い点
- ワークフローの可視性の高さにより、何をやっているのかが理解しやすい
- 後から好きに処理を追加できる柔軟性
- Redrive機能により障害復旧が簡単
ツールの課題点
- 学習コストの高さ
- ユースケースや要件が満たせるかは、Step Functionsの深い理解が必要になる
- 「Step Functionsが」というよりは、Apache Airflowなどの他のWFエンジンも当然ながら学習コストは高いので、複雑なものを使うのであればそれなりの導入コストは高いという結論に帰結する
- AWSに慣れていない人が使うとIAM回りなどのよく躓くポイントと合わさることで、詰まっている時間が長くなるので、PoCをする時などある程度の時間を確保する必要がある
- スケーラビリティの上限やQuota制限
- Standard ModeのStartExecution制限(150/秒)
- Express Modeの実行時間制限(5分)
- 256KB/1MB制限によるパラメータ渡しのためにS3経由の実装が必要
- トラフィックが極端に多い環境ではコストが嵩む
- Standard ModeはState遷移数に応じた従量課金になるので、大量の処理でコストが増加する可能性がある
- Express Modeは時間による課金であり、Standard Modeよりも制約がきつい分やすく出来るが、一方でAtLeastOnce特性による重複実行を回避するロジックを埋め込む必要が出てくるのが難点
ツールを検討されている方へ
Step Functionsが向いているケース
- ワークフローの可視性を重視する場合
- 将来的のワークフローの拡充の余地を残す必要がある場合
- 処理完了後の追加処理が必要になる可能性がある場合
- 失敗した処理の再実行が頻繁に必要な場合
代替案を検討すべきケース
- AWSをそもそも利用していない場合
- 150実行/秒を超える極めて高いスループットが必要な場合
- 256kb以上のデータがState間のパラメータとして渡される場合、外部ストレージを経由する必要があるがそれを許可できない場合
- シンプルな非同期処理のみの場合(SQS/SNSなどのPub-Subで実現したほうがよい)
今後の展望
- 現時点ではまだ通知処理が基盤に移行しきれておらず、北米のAWS障害も移行できていない部分は影響を受けてしまったため、移行を完遂すること
- 通知基盤から送られたメールの送達率や開封率などを集計し、利用者側に公開することで、基盤としての利便性を向上させていきたい
MOSH株式会社 / doriven
メンバー / バックエンドエンジニア / 従業員規模: 51名〜100名 / エンジニア組織: 11名〜50名
MOSH株式会社 / doriven
メンバー / バックエンドエンジニア / 従業員規模: 51名〜100名 / エンジニア組織: 11名〜50名
レビューしているツール
目次
- アーキテクチャ
- 導入の背景・解決したかった問題
- 活用方法


