CosmosDB+Azure Functions+SignalRでサーバーレスなリアルタイム通信してみる
個人プロジェクトで、リアルタイム通信をしながらデータのDBに保存したいよね、みたいな要望が発生
せっかくなのでAzureを使ってサーバーレスにやっていきたいし、SignalRとかCosmosDBみたいなサービスを使ってみたいってなった
構成はこんな感じに考えている
SignalRには接続のために/negotiate APIを露出させないといけない
あとCosmosDBの中身をGETするAPIもほしいよねって感じ
クライアントはUnityを想定している
Unityでsignalrを扱うのは記事が少なくて怖いんだけど、せっかくなのでやってみる
まずはデータ保存を置いておいて、
とりあえずWebクライアントで簡単なやり取りができるソケット通信構成を作ってみる
VSCodeでTypeScriptでAzure Functionを作成
簡単にnegotiateとhttpTrigger関数を作成した
今のところ参考にしているのはかずきさんのブログ
CosmosDB+Azure FunctionsはMLSAのエントリを参考にしようと思っている
かずきさんのブログ曰く、SignalR用のextentionsを入れなくてはいけないらしいので
host.jsonのextentionBundleセクションを削除して、以下のコマンドでインストール
func extensions install --package Microsoft.Azure.WebJobs.Extensions.SignalRService --version 1.6.0
SignalR
手元の環境でデバッグしようと思ったら警告が出た
どうやらNode.jsのバージョンが推奨じゃないらしい、なんだと......
For detailed output, run func with --verbose flag.
[2021-12-11T08:24:03.072Z] Debugger listening on ws://127.0.0.1:9229/52e56bd0-46f1-4bf6-9707-6ac2a7c8917e
[2021-12-11T08:24:03.074Z] For help, see: https://nodejs.org/en/docs/inspector
[2021-12-11T08:24:03.128Z] C:\Users\user\AppData\Roaming\npm\node_modules\azure-functions-core-tools\bin\workers\node\dist\src\nodejsWorker.js:35
[2021-12-11T08:24:03.137Z] throw message;
[2021-12-11T08:24:03.139Z] ^
[2021-12-11T08:24:03.141Z] Incompatible Node.js version (v16.13.0). Refer to our documentation to see the Node.js versions supported by each version of Azure Functions: https://aka.ms/functions-node-versions
確かに公式だとv14.xが推奨と書かれている
Node.jsのバージョンを管理するには有名なnというパッケージがあるけど
Windowsでは使えないみたい
かわりにnvm for Windowsなるものを使う
普通に使っていればnode v14.18.2をインストールできた
しかしなぜかnvm use 14.18.2
で変な文字化けと共にexit status 5とか出てきた
これはシェルを管理者権限で起動することで解決で切るっぽい
nodeのバージョンを変えたら無事AzureFunctionsのデバッグができた
SIgnalRのリソースを作っていく
signalR関連の実装をしたら突然ローカルで動かなくなってしまった(あまり検証できていない)
クラウドにデプロイしてもなぜかfunctionsのapiが404になってしまう
結局SignalR関連のextsntionを入れるためにhost.jsonじゃなくてcsprojが生えてたんだけど
なんかそれのせいでいろいろ動かなかったので
思い切ってhost.jsonを初期状態に戻したら普通に動いた(なんで)
そしてなぜか手元でずっと「value cannot be null(parameter key)」だったのだけど
context.bindings.signalRMessages
の最後のsをずっと抜いていた
これだからanyはよ~~~~~~~~~~~~(憤怒
とにかく解決してよかった
とりあえずテスト用のVueアプリを作っている
まだテストはできていないけどViteからテンプレ作ってAzure SWAにデプロイできた
Vueクライアントでhttp飛ばしたりsignalrのコネクション張ったりしているけど
なぜかsignalrのメッセージが飛んでこないことが分かった
見てみると、なぜかhttpは送れているものの
SignalRにsendされていない気がしていた
つまりvueクライアントのconnection.onが反応していないのはそれが悪いのではなく
AzureFunctionsからsignalrに送れていない気がする
メトリックのmessage countが0のままだった
色々試行錯誤した結果、以下の記事通りにしたら動作した!
変更内容としては、まずPostMessage関数のfunction.jsonを以下のようにした。
{
"bindings": [{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": ["get", "post"]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"type": "signalR",
"name": "$return",
"hubName": "chat",
"connectionStringSetting": "SignalRConnection",
"direction": "out"
}
],
"scriptFile": "../dist/PostMessage/index.js"
}
そして関数を以下のようにした
import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import { SignalRMessage } from "../types/SignalRMessage";
const httpTrigger: AzureFunction = async function (
context: Context,
req: HttpRequest
): Promise<SignalRMessage> {
return {
target: "message",
arguments: [req.body],
};
};
export default httpTrigger;
なんだろう、公式ドキュメントにあったものとかずきさんのブログに合ったものは同じ記法だったのに対して
今回はreturnしている
この記法を知らないです
SignalRに関してはクリアしたので
次はCosmosDBとUnityクライアントを作っていきたい
UnityでSignalRを使うためにはこちらを参照したい
公式を参考にしてやってみたら普通にできた
イイ感じ
最後にCosmosDBのデータを引っ張ってくるエンドポイントが欲しかったので作った
AzureFunctinonsで作ったが、ちょっと公式だけだと説明が足りなかった部分がある
参照した公式docs→
ここでは特定のqueryパラメータに応じてidを選択したり
sqlQueryを実行したドキュメントの取得方法が書かれている
問題の「全部取得する」ってどうするの......?
ってなったんだけど、結論から言うとfunctions.json
でidもsqlQueryも指定しなければ
全データが降ってくるっぽい
これにて欲しい機能は全部実装できた
- SignalRと接続確立(/negotiate)
- httpトリガーでSignalrにブロードキャスト
- httpトリガーでCosmosDBに保存
- cosmosDBからのデータ取得
- これらのテストをVite-ts環境のVue3で検証&Azure SWAにデプロイ
- Functionsは全部ローカル開発してGithubActionsでCI/CD
結構いい感じにモダンなサーバーレス開発になったのでは?