Azure Functions(isolated)でCosmosDBトリガーを実装する

Azure

Azure Functionsは様々な方法でトリガーすることができます。そのうちの1つにCosmosDBトリガーが存在します。CosmosDBのアイテムが変更(追加・更新・削除)された際に、Azure Functionsを呼び出せます。

今回はisolatedなAzure FunctionsをターゲットにCosmosDBトリガーを実装してみたいと思います。

結論

  • Azure Functions CosmosDBトリガーは、CosmosDBの変更フィードを利用する
  • 変更フィードには「最新バージョンの変更フィード」と「すべてのバージョンと削除の変更フィード」の2種類あり、Azure Functions CosmosDBトリガーでは「最新バージョンの変更フィード」のみ対応している(2023年9月時点)
  • 「最新バージョンの変更フィード」では、CosmosDBアイテムの追加・更新内容がAzure Functionsに伝えられる
  • データベース名やコンテナ名、接続文字列などの情報を設定するだけで、簡単にCosmosDBトリガーのAzure Functionsを実装できる。

CosmosDBの変更フィードについて

CosmosDBではデータの追加・更新・削除などの変更が記録されます。この変更をアプリで受信して処理を行う、いわゆるイベント駆動を実現できます。具体的な使用例としては以下のユースケースが考えられます。

  • 削除されたアイテムをストレージなどに保存する
  • アイテムの追加や更新を検知して通知する

この変更フィードですが、現在「最新バージョンの変更フィード」と「すべてのバージョンと削除の変更フィード」の2種類のモードが存在します。簡単に違いを説明すると、「最新バージョンの変更フィード」は追加・更新のみで、「すべてのバージョンと削除の変更フィード」は追加・更新・削除のすべての情報が取得できます。「すべてのバージョンと削除の変更フィード」は現在プレビューです。

変更フィードの詳細については下記のAzureドキュメントが参考になります。

変更フィードの読み取りについて

変更フィードを読み取る方式についても、変更が自動的にアプリにプッシュされる「プッシュモデル」と、自ら変更を取得しに行く「プルモデル」の2種類があります。手軽さの観点から「プッシュモデル」を利用することが推奨されています。

さらにプッシュモデルとしても、「Azure Functions CosmosDBトリガー」と「変更プロセッサライブラリ」を利用する2種類の方法があります。変更プロセッサライブラリは変更フィードを受信してアプリに連携するコードを自ら実装します。一方Azure FunctionsのCosmosDBトリガーは変更プロセッサをAzure側が実装してくれているためより簡単に連携することができます。

今回は「最新バージョンの変更フィード」を「プッシュモデル」である「Azure Functions CosmosDBトリガー」で読み取ってみたいと思います。

ちなみに2023年9月20時点で、「すべてのバージョンと削除の変更フィード」はAzure Functions CosmosDBトリガーが未対応です。

環境

言語.NET 6(6.0.413)
関数の言語isolated(分離ワーカープロセス)
CosmosDBServerless
OSWindows 11

Azure FunctionsはローカルのWindows VM上で動かしています。

Azure Functions CosmosDBトリガーの実装

全体的な流れは下記Azureドキュメントに従います。

パッケージの追加

isolatedなAzure FunctionsでCosmosDBトリガーを使用するためには、「Microsoft.Azure.Functions.Worker.Extensions.CosmosDB」をプロジェクトに追加します。

環境変数の設定

Azure Functionsで利用する変数を環境変数に設定します。ここではlocal.settings.jsonに設定します。このファイルに設定された変数はAzure Functions実行時に自動的に環境変数として読み取られます。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "COSMOS_DB_NAME": "testdb",
    "COSMOS_CONTAINER_NAME": "container3",
    "COSMOS_LEASE_CONTAINER_NAME": "leases",
    "COSMOS_CONNECTION_STRING": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
  }
}

関数(CosmosDBトリガー)の追加

以下のようにCosmosDBトリガーで実行される関数を作成します。ここでリースコンテナ名を指定してかつ自動作成する設定にしています。CosmosDBトリガーでは変更フィードの読み取り状態を記憶しておく場所(コンテナ)が必要になります。下記のように設定することで、指定した名前で自動的に作成してくれます。

        [Function("Cosmos")]
        public void RunCosmos([CosmosDBTrigger(
            databaseName:"%COSMOS_DB_NAME%",
            containerName:"%COSMOS_CONTAINER_NAME%",
            Connection = "COSMOS_CONNECTION_STRING",
            LeaseContainerName ="%COSMOS_LEASE_CONTAINER_NAME%",
            CreateLeaseContainerIfNotExists = true)] string cosmosItems)
        {
            // 変更フィードからのデータをそのまま表示
            _logger.LogInformation(cosmosItems);
            var items = JsonSerializer.Deserialize<List<CosmosEntity>>(cosmosItems);
            if (items is not null)
            {
                foreach (var item in items)
                {
                   // nameプロパティの値を表示
                    _logger.LogInformation($"Name : {item?.Name}");
                }
            }

        }

動作確認

以下のようにidとnameプロパティを持ったアイテムをコンテナに追加します。またその直後にnameをtest1に更新します。

アイテムの追加・変更が完了したら、Azure Functionsの関数が2回呼び出されているため、ログから動作を確認します。赤で囲んだ範囲が追加、橙で囲んだ範囲が更新のログになります。追加や更新の情報がJSON文字列としてで渡されていることが分かります。またそのJSON文字列をデシリアライズして得られたnameプロパティも正常に出力されています。

前章でCosmosDBトリガーにはリースコンテナが必要で、そのリースコンテナは自動的に作成されると説明しました。では実際に作成されたリースコンテナを見てみましょう。

leasesというコンテナが作成されて2件アイテムが追加されていました。そのうちの1つのデータを見てみます。詳細は不明ですが、変更フィード読み取りの情報が格納されているようです。

はまった点

CosmosDBトリガー自体は非常に簡単に設定できますが、一部はまった個所があるのでそれについて記載します。

Azure Functionsの起動に失敗する

ドキュメント通りに実装して、ローカル端末でFunctionsを起動したところ、下記のようなエラーが発生して正常起動に失敗しました。

Could not load type 'Microsoft.Azure.WebJobs.ParameterBindingData' from assembly 'Microsoft.Azure.WebJobs.Extensions

最初に間違って「Microsoft.Azure.WebJobs.Extensions」という異なるパッケージを入れてしまったため、キャッシュか何か残っているのかなと思い、プロジェクトのbinディレクトリなどをすべて削除しましたが結果は変わりませんでした。

さらに調査を進める中で、CosmosDBトリガーではParameterBindingDataは機能しないため、CosmosDBトリガーでは使わないようにする必要があるというissueが上がっていました。

しかし、このissueは2023年1月ころには対応されており、私が使用しているパッケージも最新で上記のissueは解決済みであります。

それから他に何か最新ではないものはあるかなと探していたところ、Azure Functions Core Toolsが数か月前にインストールしてそのままであることに気が付きました。淡い期待を抱きつつ「4.0.4829」から「4.0.5348」最新化しました。すると何とか起動に成功しました。

何かあったらまずは最新化ですね。(最新バージョンにすることで発生するバグもあるので一概に最新化がいいとは言えませんが。)

変更フィードが文字列で読み取られる

Azureドキュメントでは、変更フィードの型は「IReadOnlyList<独自クラス>」で取得できるとあります。しかし実際に実行してみるとJSON文字列として取得されていました。

さまざまなCosmosDBトリガーのサンプルも確認しましたが、皆ちゃんとデシリアライズされているようでした。なぜ今回文字列のままであったのかはまでは分かっていませんので、分かり次第追記していこうと思います。

まとめ

今回はisolatedなAzure FunctionsのCosmosDBトリガーを試してみました。変更フィードがJSON文字列のままデシリアライズされなかったのは腑に落ちていませんが、Azure FunctionsであればCosmosDBへの接続情報を指定するだけで簡単に実装できます。Functions以外で実装する場合は自分で変更プロセッサライブラリを作成する必要があるため、この手軽さはAzure Functionsを利用するメリットです。

変更プロセッサを利用して変更フィードを読み取る方法についても以下で試していますので、よろしければご確認ください。

コメント