こんにちは!mayukorin です.今日は,Cloud Run での WebSocket 接続のタイムアウトに対処するための方法についてお話しさせていただこうと思います!
先に結論
- Cloud Run では, WebSocket 接続は 30秒 でタイムアウトする1.
- WebSocket では,このようなタイムアウトに対応するために Ping and Pong フレーム が定義されている2.
- クライアントまたはサーバーがpingを送信
- サーバーまたはクライアントがpongを送信
- これを定期的に繰り返すことで,クライアント・サーバー間の接続を維持できる.
- Cloud Run の場合は,30 秒未満 の間隔で ping/pong を行えばよい
背景
WebSocket を使ったサービス3をデプロイしたのですが,CloudRun上で何故か30秒でWebSocketの接続が切断されてしまうという現象が起きていました.ローカルで動かすときにはそんなことは起きなかったので謎でした.
ローカルでCloudRunにアクセスしても同じように30秒で切断されてしまったので,CloudRun側の問題であると確信しました.
Cloud Run では, WebSocket 接続は 30秒 でタイムアウトする
色々調べてみると,Google Cloud のドキュメントに以下のようなことが書かれていました.
WebSocket 接続のタイムアウトは、ロードバランサの構成可能なバックエンド サービス タイムアウトによって異なります。デフォルトは 30 秒です。このタイムアウトは、WebSocket 接続が使用中かどうかに関係なく WebSocket 接続に適用されます。
まさにこれが30秒で接続が切断される原因でした!
WebSocket で定義されている Ping and Pong フレーム
このようなタイムアウトに対応するために,WebSocket では Ping and Pong フレーム が定義されています2.これは,クライアント・サーバー間の接続を維持する4 などの用途で使われるもので,以下のような手順からなります.
- クライアントまたはサーバーがpingを送信
- サーバーまたはクライアントがpongを送信
- これを定期的に繰り返すことで,クライアント・サーバー間の接続を維持できる.
Cloud Run では接続が30秒でタイムアウトしてしまうので,このping/pongを 30秒未満 の間隔で行えば接続が維持できるということになります!
ping/pong の仕組みは,自前で実装する必要があります.例えば,サーバー側からpingを送信したい場合 && サーバー側でGoのgorilla/webSocket を使っている場合は,こちらの記事が大変参考になります.他の言語でwebSocketを使っている場合にも,検索すれば出てくると思います(無責任でごめんなさい...)
結論(再掲)
- Cloud Run では, WebSocket 接続は 30秒 でタイムアウトする1.
- WebSocket では,このようなタイムアウトに対応するために Ping and Pong フレーム が定義されている2.
- クライアントまたはサーバーがpingを送信
- サーバーまたはクライアントがpongを送信
- これを定期的に繰り返すことで,クライアント・サーバー間の接続を維持できる.
- Cloud Run の場合は,30 秒未満 の間隔で ping/pong を行えばよい
参考
- https://cloud.google.com/load-balancing/docs/https#websocket_support
- https://websockets.spec.whatwg.org/#ping-and-pong-frames
- https://qiita.com/dlstjq7685/items/564f28147daf20a6496d