Cosmos DB Binding for Azure Functions

このエントリは2019/05/13現在の備忘録であり、以下のドキュメントの内容に対するメモです。将来この機能や設定方法が変わる可能性はあります。対象はFunction 2.xです。また、以下のコード例はいずれもJavaで記述しています。

Azure Functions 2.x の Azure Cosmos DB バインド
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-cosmosdb-v2

Functionsをローカル環境でテストする場合(http://localhost:7071/…)、以下の前提条件を満たしておく必要があります。

Azure Functions バインド拡張機能を登録する
ローカル開発の Azure Functions Core Tools
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-register#local-development-azure-functions-core-tools

このドキュメントには記載がありませんが、実際にはService Fabric SDKも必要です。必ずダウンロードしてインストールしておく必要があります。

Windows で開発環境を準備する(OS X、Linuxでの開発の場合は、下記URLでドロップダウンボックスでLinux、OS Xを選択します)
https://docs.microsoft.com/ja-jp/azure/service-fabric/service-fabric-get-started

あと、Cosmos DBへの接続のための接続文字列は、ローカルテスト環境とAzure上では設定箇所が違うのでご注意を。

  • ローカルテスト環境:local.settings.json
  • 本番環境:Application settings > Connection strings

Trigger

Azure Cosmos DB のトリガーは Azure Cosmos DB 変更フィードを使用して、パーティション間の挿入と更新をリッスンします。 変更フィードは、削除ではなく挿入と更新を発行します。

Azure Functions 2.x の Azure Cosmos DB バインド – トリガー
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-cosmosdb-v2#trigger

変更されたドキュメントは変更順にリストとして出力されます。@CosmosDBTriggerをアノテーションとして付加したFunctionが定期的に変更リストをポーリングしており、リストに追加があれば、そのFunctionsのロジックが動作します。

package cosmos2functions;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.annotation.CosmosDBTrigger;
import com.microsoft.azure.functions.annotation.FunctionName;

import java.util.List;

public class Function {
    @FunctionName("cosmosDBMonitor")
    public void cosmosDbLog(
            @CosmosDBTrigger(
                    name = "CosmosDB2Functions",
                    databaseName = "database",
                    collectionName = "Items",
                    leaseCollectionName = "Leases",
                    createLeaseCollectionIfNotExists = true,
                    connectionStringSetting = "AzureCosmosDBConnection")
                    List<String&gt; items,

            final ExecutionContext context
    ) {
        context.getLogger().info(items.size() + " item(s) is/are inserted.");
        if (!items.isEmpty()) {
            items.stream().forEach(s -&gt;context.getLogger().info("Element: " + s));
        }
    }
}

取得できるのは変更された結果のドキュメントです。Stringとして取得してJSONObjectに変換すれば、変更データを取得できます。

なお、アノテーションで設定するプロパティは以下のドキュメントに記載があります。

CosmosDBTrigger Interface
https://docs.microsoft.com/en-us/java/api/com.microsoft.azure.functions.annotation.CosmosDBTrigger?view=azure-java-stable

ドキュメントに記載のないデフォルト値は以下の通りです。

プロパティデフォルト値
name
dataType“”
databaseName
collectionName
leaseConnectionStringSetting“”
leaseCollectionName“”
leaseDatabaseName“”
createLeaseCollectionIfNotExistsfalse
leasesCollectionThroughput-1
leaseCollectionPrefix“”
checkpointInterval-1
checkpointDocumentCount-1
feedPollDelay5000
connectionStringSetting
leaseRenewInterval17000
leaseAcquireInterval13000
leaseExpirationInterval60000
maxItemsPerInvocation-1
startFromBeginningfalse
preferredLocations“”

Input

SQL API を使用して 1 つ以上の Azure Cosmos DB ドキュメントを取得して関数の入力パラメーターに渡します。ドキュメント ID またはクエリ パラメーターは、関数を呼び出したトリガーに基づいて決定することができます。

Azure Functions 2.x の Azure Cosmos DB バインド – 入力
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-cosmosdb-v2#input

動的な条件設定のために、Query ParameterもしくはPath Parameterで渡す値を指定できます。ドキュメント上はPath Parameterをルートデータと表現しています。Cosmos DBからPOJOもしくはStringとしてデータを取得できます。

Query Parameter (+ SQL Query)

Query Parameter(以下の例ではaddress)をFunctionに渡しています。Function内では、指定されたAddressをwhere句に指定するSQL Queryを発行し、結果をPOJOとして取得、HTTP Responseとして返しています。

このFunctionには、 <Function App URL>/api/cosmosDBInputMonitor でアクセスできます。

// Itemというクラスを作成しておく

@FunctionName("cosmosDBInputMonitor")
public HttpResponseMessage cosmosdbQuery(
        @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<String&gt;&gt; request,
        @CosmosDBInput(
                name = "CosmosDB2Functions",
                databaseName = "database",
                collectionName = "Items",
                partitionKey = "{Query.address}",
                sqlQuery = "select * from Items r where contains(r.address, {address})",
                connectionStringSetting = "AzureCosmosDBConnection")
                Item[] items,
        final ExecutionContext context
) {
    if (Optional.of(items).isPresent()) {
        return request.createResponseBuilder(HttpStatus.OK)
                .header("Content-Type", "application/json")
                .body(items)
                .build();
    } else {
        return request.createResponseBuilder(HttpStatus.NOT_FOUND)
                      .body("{\"error\":\"Not found\"}")
                      .build();
    }
}

Path Parameter (+ SQL Query)

以下の例はPath Parameterで指定する例です。この例では、

route = items/{address}

と設定しているため、このFunctionには、 <Function App URL>/api/items/{address} でアクセスできます。

// Itemというクラスを作成しておく

@FunctionName("cosmosDBInputMonitor2")
public HttpResponseMessage cosmosdbQuery2(
        @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET},
                authLevel = AuthorizationLevel.ANONYMOUS,
                route = "items/{address}")
                HttpRequestMessage<Optional<String&gt;&gt; request,
        @CosmosDBInput(
                name = "CosmosDB2Functions",
                databaseName = "database",
                collectionName = "Items",
                sqlQuery = "select * from items r where contains(r.address, {address})",
                connectionStringSetting = "AzureCosmosDBConnection")
                Items[] items,
        final ExecutionContext context
) {
    if (Optional.of(items).isPresent()) {
        return request.createResponseBuilder(HttpStatus.OK)
                .header("Content-Type", "application/json")
                .body(items)
                .build();
    } else {
        return request.createResponseBuilder(HttpStatus.NOT_FOUND)
                      .body("{\"error\":\"Not found\"}")
                      .build();
    }
}

アノテーションで設定するプロパティは以下のドキュメントに記載があります。

CosmosDBInput Interface
https://docs.microsoft.com/en-us/java/api/com.microsoft.azure.functions.annotation.cosmosdbinput?view=azure-java-stable

ドキュメントに記載のないデフォルト値は以下の通りです。

プロパティデフォルト値
name
dataType“”
databaseName
collectionName
id“”
sqlQuery“”
connectionStringSetting
partitionKey“”

Output

Azure Cosmos DB 出力バインドを使用すると、SQL API を使って Azure Cosmos DB データベースに新しいドキュメントを記述できます。

Azure Functions 2.x の Azure Cosmos DB バインド – 入力
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-cosmosdb-v2#output

@CosmosDBOutput アノテーションをつける場合、

  • Functionの戻り値をCosmos DBに格納することを意図している場合は、メソッドに注釈をつける
  • Outputバインディングを使ってCosmos DBに格納することを意図している場合は、OutputBindingクラスインスタンスに注釈をつける

という注意事項があります。

戻り値を格納する

POSTで複数の項目を入れて、Echo backするようなFunctionです。このFunctionの戻り値をCosmos DBに格納しています。

// 戻り値を格納したいので、 @CosmosDBOutputは外
@FunctionName("output1")
@CosmosDBOutput(name = "CosmosDB2Functions",
        databaseName = "database",
        collectionName = "Items",
        connectionStringSetting = "AzureCosmosDBConnection")
public Item[] echo (
        @HttpTrigger(
                name = "req",
                methods = {HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<Item[]&gt;&gt; request,
        final ExecutionContext context) {
    return request.getBody().get();
}

戻り値としてrequest.getBody()ではなく、request.getBody().get()を指定しているのは、前者の場合、以下のようにvalue要素ごと格納されるからです。

{
  "value": {
    ....
  }
}

OutputBindingを利用して格納する

この場合、メソッドの引数を使ってCosmos DBにデータを格納するため、@CosmosDBOutputは引数outputItemに対して指定していることに注意する必要があります。

// OutputBindingを使うので、@CosmosDBOutputは引数outputItemに指定

@FunctionName("output2")
public HttpResponseMessage echo (
        @HttpTrigger(
                name = "req",
                methods = {HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<List<Item&gt;&gt;&gt; request,
        @CosmosDBOutput(
                name = "CosmosDB2Functions",
                databaseName = "database",
                collectionName = "Items",
                connectionStringSetting = "AzureCosmosDBConnection")
                OutputBinding<List<Item&gt;&gt; outputItem,
        final ExecutionContext context
) {
    outputItem.setValue(request.getBody().get());
    return request.createResponseBuilder(HttpStatus.CREATED)
                  .header("content-type","application/json")
                  .body(request.getBody().get())
                  .build();
}

アノテーションで設定するプロパティは以下のドキュメントに記載があります。

CosmosDBOutput Interface
https://docs.microsoft.com/en-us/java/api/com.microsoft.azure.functions.annotation.cosmosdboutput?view=azure-java-stable

ドキュメントに記載のないデフォルト値は以下の通りです。

プロパティデフォルト値
name
dataType“”
databaseName
collectionName
createIfNotExistsfalse
connectionStringSetting
partitionKey“”
collectionThroughput-1
useMultipleWriteLocationsfalse
preferredLocations“”

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中