チュートリアル: Azure Functions と Azure Web PubSub サービスを使用してサーバーレス通知アプリを作成する

Azure Web PubSub サービスは、WebSocket を使用して、リアルタイム メッセージング Web アプリケーションを作成するのに役立ちます。 Azure Functions は、インフラストラクチャを管理することなくコードを実行できるサーバーレス プラットフォームです。 このチュートリアルでは、Azure Web PubSub サービスと Azure Functions を使用して、通知シナリオでリアルタイム メッセージングを使用したサーバーレス アプリケーションを作成する方法について説明します。

このチュートリアルでは、以下の内容を学習します。

  • サーバーレス通知アプリを作成する
  • Web PubSub 関数の入力および出力のバインドを使用する
  • サンプル関数をローカルで実行する
  • 関数を Azure Function App にデプロイする

前提条件

Azure サブスクリプションをお持ちでない場合は、開始する前に Azure 無料アカウントを作成してください。

Azure へのサインイン

Azure アカウントで Azure Portal (https://portal.azure.com/) にサインインします。

Azure Web PubSub サービス インスタンスを作成する

アプリケーションは Azure 内の Web PubSub サービス インスタンスに接続します。

  1. Azure portal の左上にある [新規] ボタンを選択します。 [新規] 画面で、検索ボックスに「Web PubSub」と入力して Enter キーを押します。 (Azure Web PubSub を Web カテゴリから検索することもできます)。

    Screenshot of searching the Azure Web PubSub in portal.

  2. 検索結果の [Web PubSub] を選択し、 [作成] を選択します。

  3. 次の設定を入力します。

    設定 提案された値 説明
    リソース名 グローバルに一意の名前 新しい Web PubSub サービス インスタンスを識別するグローバルで一意の名前。 有効な文字は、a-zA-Z0-9- です。
    サブスクリプション 該当するサブスクリプション この新しい Web PubSub インスタンスが作成される Azure サブスクリプション。
    リソース グループ myResourceGroup Web PubSub サービス インスタンスの作成先となる新しいリソース グループの名前。
    場所 米国西部 近くのリージョンを選択します。
    [価格レベル] 無料 まず Azure Web PubSub サービスを無料でお試しいただけます。 Azure Web PubSub サービスの価格レベルの詳細をご覧ください。
    [ユニット数] - ユニット数は、Web PubSub サービス インスタンスで受け入れることができる接続の数を指定します。 各ユニットで最大 1,000 のコンカレント接続がサポートされます。 Standard レベルでのみ構成可能です。

    Screenshot of creating the Azure Web PubSub instance in portal.

  4. [作成] を選択して Web PubSub サービス インスタンスのデプロイを開始します。

関数をローカルで作成して実行する

  1. Azure Functions Core Tools がインストールされていることを確認します。 次に、プロジェクトの空のディレクトリを作成します。 この作業ディレクトリの下でコマンドを実行します。 次のいずれかのオプションを使用します。

    func init --worker-runtime javascript --model V4
    
  2. インストールする手順に Microsoft.Azure.WebJobs.Extensions.WebPubSub従います。

    's extensionBundle をバージョン 4.* 以降に確認または更新host.jsonして、Web PubSub のサポートを受けます。 更新するには host.json、エディターでファイルを開き、既存のバージョン拡張機能Bundle をバージョン 4.* 以降に置き換えます。

    {
        "extensionBundle": {
            "id": "Microsoft.Azure.Functions.ExtensionBundle",
            "version": "[4.*, 5.0.0)"
        }
    }
    
  3. クライアントの静的 Web ページを読み取ってホストする index 関数を作成します。

    func new -n index -t HttpTrigger
    
    • src/functions/index.js を更新して次のコードをコピーします。
      const { app } = require('@azure/functions');
      const { readFile } = require('fs/promises');
      
      app.http('index', {
          methods: ['GET', 'POST'],
          authLevel: 'anonymous',
          handler: async (context) => {
              const content = await readFile('index.html', 'utf8', (err, data) => {
                  if (err) {
                      context.err(err)
                      return
                  }
              });
      
              return { 
                  status: 200,
                  headers: { 
                      'Content-Type': 'text/html'
                  }, 
                  body: content, 
              };
          }
      });
      
  4. クライアントがアクセス トークンを含むサービス接続 URL を取得するのに役立つ negotiate 関数を作成します。

    func new -n negotiate -t HttpTrigger
    
    • src/functions/negotiate.js を更新して次のコードをコピーします。
      const { app, input } = require('@azure/functions');
      
      const connection = input.generic({
          type: 'webPubSubConnection',
          name: 'connection',
          hub: 'notification'
      });
      
      app.http('negotiate', {
          methods: ['GET', 'POST'],
          authLevel: 'anonymous',
          extraInputs: [connection],
          handler: async (request, context) => {
              return { body: JSON.stringify(context.extraInputs.get('connection')) };
          },
      });
      
  5. TimerTrigger を使用して通知を生成する notification 関数を作成します。

    func new -n notification -t TimerTrigger
    
    • src/functions/notification.js を更新して次のコードをコピーします。
      const { app, output } = require('@azure/functions');
      
      const wpsAction = output.generic({
          type: 'webPubSub',
          name: 'action',
          hub: 'notification'
      });
      
      app.timer('notification', {
          schedule: "*/10 * * * * *",
          extraOutputs: [wpsAction],
          handler: (myTimer, context) => {
              context.extraOutputs.set(wpsAction, {
                  actionName: 'sendToAll',
                  data: `[DateTime: ${new Date()}] Temperature: ${getValue(22, 1)}\xB0C, Humidity: ${getValue(40, 2)}%`,
                  dataType: 'text',
              });
          },
      });
      
      function getValue(baseNum, floatNum) {
          return (baseNum + 2 * floatNum * (Math.random() - 0.5)).toFixed(3);
      }
      
  6. プロジェクトのルート フォルダーにクライアントのシングル ページ index.html を追加し、コンテンツをコピーします。

    <html>
        <body>
        <h1>Azure Web PubSub Notification</h1>
        <div id="messages"></div>
        <script>
            (async function () {
                let messages = document.querySelector('#messages');
                let res = await fetch(`${window.location.origin}/api/negotiate`);
                let url = await res.json();
                let ws = new WebSocket(url.url);
                ws.onopen = () => console.log('connected');
    
                ws.onmessage = event => {
                    let m = document.createElement('p');
                    m.innerText = event.data;
                    messages.appendChild(m);
                };
            })();
        </script>
        </body>
    </html>
    
  7. Azure Function アプリを構成して実行する

    • ブラウザーで Azure portal を開き、先ほどデプロイした Web PubSub サービス インスタンスが正常に作成されていることを確認します。 そのインスタンスに移動します。
    • [キー] を選択し、接続文字列をコピーします。

    Screenshot of copying the Web PubSub connection string.

    関数フォルダーでコマンドを実行して、サービス接続文字列を設定します。 <connection-string> を、必要に応じて自分の値に置き換えます。

    func settings add WebPubSubConnectionString "<connection-string>"
    

    Note

    このサンプルで使用している TimerTrigger には Azure Storage への依存関係がありますが、Function がローカルで実行されているときは、ローカル ストレージ エミュレーターを使用することができます。 There was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid. のようなエラーが発生した場合は、Storage Emulator をダウンロードして有効にする必要があります。

    これで、ローカル関数をコマンドで実行できます。

    func start --port 7071
    

    実行中のログを確認するには、http://localhost:7071/api/index にアクセスしてローカル ホストの静的ページにアクセスします。

    Note

    一部のブラウザーでは、間違った URL になる https に自動的にリダイレクトされます。 レンダリングが成功しない場合は、Edge を使用して URL を再確認することをお勧めします。

Azure に関数アプリをデプロイする

関数コードを Azure にデプロイする前に、3 つのリソースを作成する必要があります。

  • リソース グループ。関連リソースの論理コンテナーです。
  • ストレージ アカウント。関数についての情報 (状態など) を維持する目的で使用されます。
  • 関数アプリ。関数コードを実行するための環境となります。 関数アプリは、ローカルの関数プロジェクトと対応関係にあります。これを使用すると、リソースの管理、デプロイ、共有を容易にするための論理ユニットとして関数をグループ化できます。

以下のコマンドを使用してこれらの項目を作成します。

  1. Azure にサインインします。

    az login
    
  2. リソース グループを作成します。または、Azure Web PubSub サービスのいずれかを再利用してスキップできます。

    az group create -n WebPubSubFunction -l <REGION>
    
  3. リソース グループとリージョン内に汎用ストレージ アカウントを作成します。

    az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
    
  4. Azure に関数アプリを作成します。

    az functionapp create --resource-group WebPubSubFunction --consumption-plan-location <REGION> --runtime node --runtime-version 18 --functions-version 4 --name <FUNCIONAPP_NAME> --storage-account <STORAGE_NAME>
    

    Note

    Azure Functions ランタイム バージョンに関するドキュメントを確認して、--runtime-version パラメーターをサポートされている値に設置します。

  5. Azure に関数プロジェクトをデプロイする:

    Azure で関数アプリを作成したら、func azure functionapp publish コマンドを使用してローカル関数プロジェクトをデプロイする準備ができました。

    func azure functionapp publish <FUNCIONAPP_NAME> --publish-local-settings
    

    Note

    ここでは、ローカル設定 local.settings.json をコマンド パラメーター --publish-local-settings と共にデプロイしています。 Microsoft Azure ストレージ エミュレーターを使用している場合は、プロンプト メッセージ App setting AzureWebJobsStorage is different between azure and local.settings.json, Would you like to overwrite value in azure? [yes/no/show] に続いて「no」と入力して、 Azure でこの値の上書きをスキップできます。 さらに、Function App の設定を [Azure portal] ->[設定] ->[構成] で更新できます。

  6. これで、URL (https://<FUNCIONAPP_NAME>.azurewebsites.net/api/index) に移動して、Azure Function App から自分のサイトを確認できます。

リソースをクリーンアップする

このアプリの使用を続けない場合は、次の手順に従って、このドキュメントで作成したすべてのリソースを削除して、課金が発生しないようにします。

  1. Azure Portal の左端で [リソース グループ] を選択し、作成したリソース グループを選択します。 代わりに、検索ボックスを使用してリソース グループを名前で検索します。

  2. 表示されたウィンドウでリソース グループを選択し、 [リソース グループの削除] を選択します。

  3. 新しいウィンドウで、削除するリソース グループの名前を入力し、 [削除] を選択します。

次のステップ

このクイックスタートでは、サーバーレス チャット アプリケーションを実行する方法について説明しました。 これで、独自のアプリケーションの作成を始められます。