How Web Push Notifications Work Internally
新着メッセージ、注文の更新、支払いのリマインダーなどの通知を目にすることがあります。
一見シンプルに見えます。バックエンドがメッセージを送信し、ユーザーがそれを受け取るだけです。
しかし実際には、このプロセスには多くの要素が関わっています。バックエンドがブラウザと直接通信することはありません。代わりに、Push Serviceを使用します。
Google ChromeはFirebase Cloud Messagingを使用し、FirefoxはMozilla Push Serviceを使用しています。
ワークフローは以下の通りです:
Backend → Push Service → Browser → Service Worker → User
以下に、ReactとGolangを使用してこのシステムを構築する方法を説明します。
The Components
- Frontend (React): 権限をリクエストし、Service Workerを登録します。
- Service Worker: ブラウザ内で動作するバックグラウンドスクリプトです。ウェブサイトが閉じられている間でもイベントを処理します。
- Backend (Golang): サブスクリプションを保存し、暗号化されたメッセージを送信します。
- Push Service: メッセージをブラウザに届ける仲介役です。
The Subscription Flow
メッセージを送信するには、サブスクリプションが必要です。
- ユーザーが権限を許可します。
- ブラウザが、エンドポイントとセキュリティキーを含むサブスクリプションオブジェクトを生成します。
- ReactアプリがこのオブジェクトをGolangバックエンドに送信します。
- バックエンドがそれをデータベースに保存します。
サーバーを識別するためにVAPIDキーを使用する必要があります。フロントエンドには公開鍵を、バックエンドには秘密鍵を使用してください。秘密鍵は決して共有しないでください。
The Implementation
Reactでは、プッシュイベントをリッスンするためにService Workerを登録します。このワーカーはバックグラウンドで動作し、データを受け取ってユーザーに通知を表示します。
Golangでは、ライブラリを使用して暗号化とVAPID認証を処理します。サーバーはデータベースからサブスクリプションを読み取り、ペイロードを暗号化してブラウザのプッシュサービスに送信します。
Scaling for Production
小規模なプロジェクトであればシンプルな構成で十分ですが、大規模なシステムではさらなる対策が必要です。
- Handle multiple devices: 1人のユーザーがスマートフォンとノートPCの両方を持っている場合があります。ユーザーごとに複数のサブスクリプションを保存してください。
- Clean up data: サブスクリプションには有効期限があります。404または410エラーが発生した場合は、そのサブスクリプションをデータベースから削除してください。
- Use Queues: 数百万人のユーザーを対象とする場合は、Kafkaなどのツールを使用してください。これにより、システムが非同期で通知を処理できるようになります。
- Implement retries: ネットワーク障害に対処するために、指数バックオフ (exponential backoff) を使用してください。
WebSocketは、ユーザーがアクティブな状態でのライブチャットに適しています。Webプッシュは、タブが閉じられているときにユーザーにリーチするのに適しています。
