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

にー兄さんにー兄さん

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に送れていない気がする

にー兄さんにー兄さん

色々試行錯誤した結果、以下の記事通りにしたら動作した!
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

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

このスクラップは2021/12/17にクローズされました