以前から興味のあった AppSync Events で簡単なイベント駆動的なWebアプリケーションを構築してみたので、どんな構成にしたかなどを整理しておきたいと思います。
AppSync Events は 2024年10月頃に GA になっているようで、それ以前は GraphQL Subscription で同様にイベント駆動的な構成を組んでいる事例が多かった印象です。
公式のドキュメントを見ると以下の掲載があり、AWS 的にもこれから同じような構成を組む際には GraphQL Subscription ではなく、AppSync Events の利用を推しているように見えます。
As of Mar 13, 2025, you can build a real-time PubSub API powered by WebSockets using AWS AppSync Events. For more information, see Publish events via WebSocket in the AWS AppSync Events Developer Guide.
※注意: AppSync Events 自体の GA は 2024年10月、上記は2025年3月に追加された WebSocket Publish 機能のアナウンス
GraphQL Subscription 構成の場合、スキーマ設計 (Mutation・Subscription の型定義) はもちろん、サブスクリプションは Mutation のトリガーに紐づく仕組みのため、対応する Mutation のリゾルバ (データソースへのリクエスト・レスポンスのマッピング定義)も別途実装する必要があり、「シンプルに Pub/Sub 的な構成にしたいだけなのに...。」という要望にうまく対応してくれたのが AppSync Events だと勝手に解釈してます。
[以下参考記事]

まず今回構成した内容ですが、frontend は CloudFront + S3 (spa), backend は API Gateway + Lambda (api), SQS + Lambda (event) で、各領域を疎結合化した構成にしています。
一部、本番運用で良くあるパターンだと、動画や画像の変換処理や決済処理などの重い処理をしたりする際に、その処理の状態をデータストアに永続化していたりすると思うので、(個人開発でコスト的にも優しい) DynamoDB を利用しそちらに書き込みの処理を行うようにしています。
このような構成にすることで、例えば以下のようなポーリング処理も不要になります。
POST: /tickets/orders でリクエスト (apiサーバでリクエストを受け付けてsqs で lambda などの別サービスへ処理を委譲)GET: /tickets/orders/<order_id>/status でn秒間隔でリクエスト (状態がstatus=completed になったら表示切り替え)サービスが大きくなり、マルチテナントで構成しつつ、且つマイクロサービス的に1リクエストで様々なサービスに依存する構成になっている場合などは、このポーリング処理が与えるインフラへの影響は徐々に無視できないものになってきたりします。
上記の構成図を踏まえてそもそもの機能に関しておさらいをしておくと、AppSync Events は従来型の GraphQL とは独立したチャンネルベースの Pub/Sub を提供しているサービスです。
従来型の GraphQL ベースの機能の場合はユーザ側でスキーマ定義をする必要があったのですが、そのあたりの定義は特に必要なく、backend から HTTP で Publish できるのが利点のようです。
WebSocket and HTTP Support
- Clients can publish events over HTTP or WebSocket, and can subscribe to channels using WebSockets.
- Event APIs provide WebSocket endpoints that enable real-time and pub/sub capabilities.
https://docs.aws.amazon.com/ja_jp/appsync/latest/eventapi/event-api-concepts.html#channel
Channels are the routing mechanism for directing events from publishers to subscribers. You can think of a channel as a "topic" or "subject" that represents a stream of related events. Clients subscribe to channels in order to receive events published to those channels in real-time. Channels are ephemeral and can be created on-demand.
大まかには、AppSync Events にチャネル (例: tickets/orders) を定義すると、HTTP Publish エンドポイントと WebSocket Subscribe エンドポイントが自動的に用意され、それらを利用してクライアント側でイベント通知を受け取るようなイメージになります。
HTTP Publish エンドポイントと WebSocket Subscribe エンドポイントについてすごく簡単に説明すると、 HTTP Publish エンドポイントは backend サービス (非同期的に動作するワーカーなど) がイベントを送信するための口です。
例えば backend サービスが非同期処理を終えたタイミングで以下のような json を AppSync Events に対して HTTP で送信するようなイメージです。
{
"channel": "tickets/orders",
"events": [{"orderId": "abc123", "status": "completed"}]
}
一方 WebSocket Subscribe エンドポイントは frontend がイベントを受信するための口です。
React などのクライアントアプリでこのエンドポイントに対して WebSocket 接続を張り、チャンネルを Subscribe しておくと、誰かが Publish したイベントがリアルタイムに流れてくるようなイメージになります。
// aws-amplify v6 を利用する場合
const channel = await events.connect("tickets/orders")
channel.subscribe({
next: (data) => console.log(data) // ← Publish されるたびに発火
})
整理するとこのようなイメージです。
| HTTP Publish | WebSocket Subscribe | |
|---|---|---|
| 使う側 | バックエンド (Lambda) | フロントエンド (React) |
| 接続方式 | 1 リクエスト送ったら終わり | 常時接続を維持 |
| 役割 | イベントを送る | イベントを受け取る |
ほか、ユーザ側は WebSocket 接続管理を AWS に委譲できるのも利点と言える気がします。
運用中のよくあるケースとしては、クライアントの接続数増加、接続切断時の処理、スケール時の接続分散など、このあたりを AppSync が引き受けてくれるため、運用的に負荷がかかりやすい部分をマネージドに保てるのも嬉しい一面です。
今回は一旦ここで区切ります。かなりざっくりではありましたが、AppSync Events の概要などを整理してみました。
次回は実際に構成した内容をコードベースで紹介できたらと思います。
AppSync Events を使用したイベント駆動アーキテクチャの実装をCDKで定義し、WebSocket通信によるリアルタイムイベント配信の構成と動作確認を紹介。
AppSync Events を用いたイベント駆動型Webアプリケーションの実装例を紹介。API Lambda、Event Lambda、フロントエンドの実装コードと、AppSync Events への Publish 時の JSON 二重シリアライズやAPI キー認証などの注意点を解説。
AWS Lambdaのエラー通知をSlackに送信する際の設計ポイントを解説。ログ永続化、Subscription Filter上限対策、コスト最適化、通知遅延を考慮し、CloudWatch Logs→Lambda→Slack通知とFirehose→S3保存の構成を採用した実装例を紹介。
AWS AIPの知見を活かし、論文PDFを構造化JSONに変換するパイプラインを構築。S3、Lambda、Step Functions、Textract、Bedrockを組み合わせ、2つの抽出経路で日本語・英語PDFを処理し、メタデータ付きの構造化データをRAGのソースとして活用する仕組みを実装。
論文PDFを構造化JSONに変換するパイプラインの経路A(Textract+Bedrock)について、各ステップの設計理由と実装を詳細に解説。出力上限問題への対処として、モデルに本文を書かせず位置情報のみ返させることで、生成時間を半減させた改善事例を紹介。