Azure FunctionsのCosmos DBトリガー

2017年のIgniteで発表されたCosmos DB関連の新機能で個人的に注目しているのが、Azure FunctionsとCosmos DBのネイティブ統合です。

Cosmos DBにはもともとChange Feedという機能がありますが、以前このブログ記事「DocumentDBのChange Feed機能を使う方法」で書いたように、Change Feedというわりには若干中途半端な機能だなと感じていました(変更イベントの検知を自分で作り込む必要があったという意味で)。

今回発表されたAzure FunctionsのCosmos DB Triggerは、まさに従来のChange Feedに足りなかった部分を補うもので、「Cosmos DBのデータ変更を自動的に検知してイベントを起こしてくれる」機能がやっと出たなという感じで少し安心しました。

ポータルでの作成方法

Azure Functionsのポータル上では既にCosmos DB Triggerの関数が作成できるようになっています。対応言語はC#とJavaScriptです(ポータルからの作成だとC#は.csxになってしまいますが)。

Function選択画面

従来の関数作成方法と同じように各種パラメータを設定すれば、とりあえず動く関数ができあがります。なお、Cosmos DBのコレクションはあらかじめ作っておき、データベース名とコレクション名はメモしてからこの画面に来た方がいいでしょう。

Function設定画面

この設定画面で「Collection name for leases」と「Create lease collection if it does not exist」いう見慣れない項目がありますが、実はここが重要なポイントになります。
Cosmos DB Triggerはその処理の裏側でChange Feed Processorという処理系を使っているのですが、その仕組み上、変更イベントを管理するためのlease collectionと呼ばれる管理用コレクションが必要となります。ここではそのlease collection名と自動作成するかどうかの設定が必要になります。

ここでコストに敏感な方は気づいたかもしれませんが、Cosmos DB Triggerを使う場合、実際のデータが入っているコレクションとは別のコレクションがもう一つ必要になることになります( =Functionの料金以外にlease collectionの料金がかかる)。まあ、リアルタイムの変更状態管理を実現するためにはやむを得ないコストだと考えましょう。

.csxでの実装

生成されるコードはこんな感じで特別なところはあまりないですが、Cosmos DB Triggerではトリガーの引数として入ってくるデータ(input)には、IDのみでなく実際に格納されているDocumentが丸ごと入ってきます。また、変更の頻度や取得タイミングによっては複数のDocumentが入ってくる可能性があるため、配列として扱う必要があります(どういうタイミングで変更が入るとコレクションになるのか等は調査中)。

#r "Microsoft.Azure.Documents.Client"
using System;
using System.Collections.Generic;
using Microsoft.Azure.Documents;
public static void Run(IReadOnlyList<Document> input, TraceWriter log)
{
if (input != null && input.Count > 0)
{
log.Verbose("Documents modified " + input.Count);
log.Verbose("First document Id " + input[0].Id); // DocumentのIDを出力
}
}
view raw run.csx hosted with ❤ by GitHub

Cosmos DB Triggerの場合は、トリガーで入ってきたデータをそのまま使って処理を実装できるので、入力バインドが不要になります。あとはロジックや出力だけ考えれば良いので楽ですね。

.csでの実装

Azure Functionsは、.csxではなく、.csで実装したいですよね。私は仕事ではcsxはほとんど使いません。Cosmos DB Triggerも.csでの実装が可能です。が、執筆時点ではまだ各種周辺ライブラリのプレビュー版をバージョンに気を使いつつ集めてこないと実現できない状態なので、静かにSDKへの本格実装を待ちたいと思います。

ちなみに.csでの実装は今のところ以下のような感じになります。が、変更される可能性も高いのであくまでも参考ということで。

using System.Collections.Generic;
using Microsoft.Azure.Documents;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
namespace ChangeFeedFunction
{
public static class RcModelFeed
{
[FunctionName("RcModelFeed")]
public static void Run([CosmosDBTrigger("dojo", "rcmodel", ConnectionStringSetting = "AzureWebJobsDocumentDBConnectionString",
LeaseCollectionName = "leases", LeaseDatabaseName = "dojo")]IReadOnlyList<Document> changeList, TraceWriter log)
{
if (changeList != null && changeList.Count > 0)
{
log.Verbose("Documents modified " + changeList.Count);
var i = 0;
foreach (var change in changeList)
{
log.Verbose("document Id of $i: " + change.Id);
log.Verbose(change.ToString()); // Document全体を出力
i++;
}
}
}
}
}
view raw RcModelFeed.cs hosted with ❤ by GitHub

このCosmos DB Triggerは、アーキテクチャ設計の幅を大きく広げる可能性があると思っており、今後の動向にも注目しています。