Closed27

CosmosDB+Azure Functions+SignalRでサーバーレスなリアルタイム通信してみる

個人プロジェクトで、リアルタイム通信をしながらデータのDBに保存したいよね、みたいな要望が発生
せっかくなのでAzureを使ってサーバーレスにやっていきたいし、SignalRとかCosmosDBみたいなサービスを使ってみたいってなった

構成はこんな感じに考えている
SignalRには接続のために/negotiate APIを露出させないといけない
あとCosmosDBの中身をGETするAPIもほしいよねって感じ

クライアントはUnityを想定している
Unityでsignalrを扱うのは記事が少なくて怖いんだけど、せっかくなのでやってみる

まずはデータ保存を置いておいて、
とりあえずWebクライアントで簡単なやり取りができるソケット通信構成を作ってみる

かずきさんのブログ曰く、SignalR用のextentionsを入れなくてはいけないらしいので
host.jsonのextentionBundleセクションを削除して、以下のコマンドでインストール

https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-register#explicitly-install-extensions
func extensions install --package Microsoft.Azure.WebJobs.Extensions.SignalRService --version 1.6.0

手元の環境でデバッグしようと思ったら警告が出た
どうやら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が推奨と書かれている

https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-node?tabs=v2#node-version

Node.jsのバージョンを管理するには有名なnというパッケージがあるけど
Windowsでは使えないみたい
かわりにnvm for Windowsなるものを使う

https://docs.microsoft.com/ja-jp/windows/dev-environment/javascript/nodejs-on-windows

nodeのバージョンを変えたら無事AzureFunctionsのデバッグができた

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のままだった

色々試行錯誤した結果、以下の記事通りにしたら動作した!

https://news.mynavi.jp/techplus/article/zeroazure-33/

変更内容としては、まず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クライアントを作っていきたい

ここでは特定のqueryパラメータに応じてidを選択したり
sqlQueryを実行したドキュメントの取得方法が書かれている
問題の「全部取得する」ってどうするの......?
ってなったんだけど、結論から言うとfunctions.jsonでidもsqlQueryも指定しなければ
全データが降ってくるっぽい

これにて欲しい機能は全部実装できた

  • SignalRと接続確立(/negotiate)
  • httpトリガーでSignalrにブロードキャスト
  • httpトリガーでCosmosDBに保存
  • cosmosDBからのデータ取得
  • これらのテストをVite-ts環境のVue3で検証&Azure SWAにデプロイ
  • Functionsは全部ローカル開発してGithubActionsでCI/CD

結構いい感じにモダンなサーバーレス開発になったのでは?

このスクラップは5ヶ月前にクローズされました
ログインするとコメントできます