Azure SignalR Service を仕事で少し使ったときに、設定が増えていることに気が付いたので調べたのですが、中の人に聞くまで情報がほぼ無かったのでメモとして残します。そして Serverless mode がかなり良かったので、それの紹介も簡単にですがします。
チャックさん曰く、ちょっと前から Service mode を選べるようになっていたらしいです。
Azure Portal には最小限の説明しかなかったので、具体的にどのように変わるのか分かりませんでした。ドキュメントも無いみたいでしたし、とりあえず Default で良いかなという気分がしてくる設定です。
バックエンドが必要ない場合には Serverless を選択すればよいと言われても、何かが変わる気がしません。SignalR Service の仕組みは公開されているので、読んでおくとこの先の理解が容易になります。
SignalR Service で指されるサーバーというのは、ASP.NET Core SignalR で実装された Hub を持つアプリケーションのことを指しています。Azure SignalR Internals にもあったように、クライアントとサーバーの両方が SignalR Service に対しての接続を保持します。
サーバー接続が存在する場合には、クライアントからのメッセージは必ずサーバーに実装された Hub を実行し、その結果でメッセージの送信などが行われます。このようにサーバー側で Hub の実装が必要だったのが、これまでの ASP.NET Core SignalR でした。
それに対して Serverless というのはクライアント向けの API だけで動作するモードとなります。この辺りの挙動がいまいち想像つかなかったので、オリジナルの SignalR 開発者の David Fowler 氏に Azure SignalR Service チームの Ken Chen 氏を紹介していただき詳しく教えてもらいました。
Default is where you must have a server connected to the service, in this mode if you don't have a server client connections will fail. Serverless mode is the opposite, you cannot have a server connection, all attempts to establish a server connection will fail.
— Ken Chen (@chenkennt) 2019年1月25日
For example, server connections may get dropped for some reason. It's not easy for user to discover it as clients can still connect in a serverless mode. That's why we came up with the two new modes where the behaviors are more clearly defined.
— Ken Chen (@chenkennt) 2019年1月25日
要するに Azure SignalR Service はサーバーが落ちていてもクライアントの通信は維持されたままなので、この挙動では障害が発生しても切断やエラーにならないので困るよね、ということです。当たり前ですが、これまでの SignalR ではサーバーが落ちた場合は接続が切れます。
さらに Azure SignalR Service ではクライアントだけでも通信が行えるので、チャットのようにクライアントから双方向で通信する場合には、切断を検知する方法が今までは存在しなかったということになります。
実際に Default に設定した SignalR Service を用意して、サーバーを起動した後に別クライアントの接続を行っている状態で、サーバーを落とすと以下のようにエラーが通知されます。
クライアント側では Closed イベントが実行されるので、エラーの通知やリトライを行えば良いです。
そして Serverless に設定した状態でサーバーを起動させると、正常に立ち上がらずにエラーとなります。
返ってきたエラーメッセージには Serverless mode ではサーバー接続が行えないと書いてあります。
ここまでに調べた情報をまとめると以下のようになります。分かってしまえば単純です。
- Default の場合
- サーバーの接続が切れた場合にクライアントの接続も切断される
- 実際には SignalR Service からリトライリクエストが投げられる
- Serverless の場合
- そもそもサーバーが接続しようとするとエラーを返す
- Classic の場合
- これまで通りの挙動。特にエラーになったり、切断されたりしない
現時点では ASP.NET Core SignalR で実装しているアプリケーションの場合は Default を使い、Azure Functions で SignalR Binding を使う場合には Serverless を設定しておけば良い感じです。
SignalR での Hub 実装は割と 1,2 行で終わるケースが多かったので、そういったケースでは SignalR Binding を使うと驚くほど簡単にリアルタイム通信のアプリケーションを実装できるはずです。GitHub にある Serverless Chat のサンプルが非常に良い出来だったので、非常に参考になります。
SignalR Service への接続周りは Azure Functions の SignalR Binding で行えば、クライアント側実装は JavaScript が書ければよいので Azure Storage の Static Website Hosting で十分ということになります。これで Serverless mode と呼ばれている理由が理解できますね。
特に Azure Functions はイベントドリブンなので、SignalR Service とかなり相性が良いです。そしてリアルタイムで状態が変わっていくので Vue.js などと組み合わせると、更に良い感じでアプリを作れるはずです。