Cosmos DB Binding for Azure Functions

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

Azure Functions 2.x 以降での Azure Cosmos DB のトリガーとバインドの概要 / Azure Cosmos DB trigger and bindings for Azure Functions 2.x and higher overview
https://docs.microsoft.com/azure/azure-functions/functions-bindings-cosmosdb-v2

Functionsをローカル環境でテストする場合(http://localhost:7071/…)、Azure Functions バインド拡張機能をインストールしておく必要がある。

Azure Functions バインド拡張機能を登録する / Register Azure Functions binding extensions
https://docs.microsoft.com/azure/azure-functions/functions-bindings-register

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

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

Trigger

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

Azure Functions 2.x 以降での Azure Cosmos DB のトリガー / Azure Cosmos DB trigger for Azure Functions 2.x and higher
https://docs.microsoft.com/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> items,
            final ExecutionContext context
    ) {
        context.getLogger().info(items.size() + " item(s) is/are inserted.");
        if (!items.isEmpty()) {
            items.stream().forEach(s ->context.getLogger().info("Element: " + s));
        }
    }
}

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

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

CosmosDBTrigger Interface
https://docs.microsoft.com/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 の入力バインド / Azure Cosmos DB input binding for Azure Functions 2.x and higher
https://docs.microsoft.com/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>> 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>> 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/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 の出力バインド / Azure Cosmos DB output binding for Azure Functions 2.x and higher
https://docs.microsoft.com/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[]>> 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>>> request,
        @CosmosDBOutput(
                name = "CosmosDB2Functions",
                databaseName = "database",
                collectionName = "Items",
                connectionStringSetting = "AzureCosmosDBConnection")
                OutputBinding<List<Item>> 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/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 アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

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

%s と連携中