EventGrid Triggerの作成(Spring Boot)

Spring Boot でAzure FunctionsのEventGrid Triggerを実装して、ローカルで動作確認する手順を示す。

プロジェクトの作成方法については、以下の記事参照。

olafnosuke.hatenablog.com

バージョン

Spring Boot:2.7.5
Java:17

ファンクションを新規追加する

ファンクションを新規追加する場合は、HandlerクラスとFunctionクラスをそれぞれ追加する。
この時、Handlerクラスはorg.springframework.cloud.function.adapter.azure.FunctionInvoker<I, O>を継承し、Functionクラスはjava.util.function.Function<T, R>を実装して作成する。
各ファンクションでDIしたいbeanがある場合はConfigurationクラスを作成する。

Configクラスの作成

ファンクションクラスをbean登録するためのConfigクラスを作成する。
その他処理を行うにあたって必要なクラスがある場合は記述する。

// Configクラス
@Configuration
public class EventGridConfiguration {
    @Bean
    public EventGridFunction eventgrid() {
        return new EventGridFunction();
    }
}

EventGridTriggerのイベント情報を保持するクラスの作成

イベント情報が以下のような形式で送られてくるので、マッピングするためのEventSchemaクラスを作成する。

[
    {
        "topic": "/subscriptions/{subscription-id}/resourceGroups/Storage/providers/Microsoft.Storage/storageAccounts/my-storage-account",
        "subject": "/blobServices/default/containers/my-file-system/blobs/new-file.txt",
        "eventType": "Microsoft.Storage.BlobCreated",
        "eventTime": "2017-06-26T18:41:00.9584103Z",
        "id": "831e1650-001e-001b-66ab-eeb76e069631",
        "data": {
            "api": "CreateFile",
            "clientRequestId": "6d79dbfb-0e37-4fc4-981f-442c9ca65760",
            "requestId": "831e1650-001e-001b-66ab-eeb76e000000",
            "eTag": "\\"0x8D4BCC2E4835CD0\\"",
            "contentType": "text/plain",
            "contentLength": 0,
            "contentOffset": 0,
            "blobType": "BlockBlob",
            "url": "http://127.0.0.1:10000/devstoreaccount1/java/test.zip",
            "sequencer": "00000000000004420000000000028963",
            "storageDiagnostics": {
                "batchId": "b68529f3-68cd-4744-baa4-3c0498ec19f0"
            }
        },
        "dataVersion": "2",
        "metadataVersion": "1"
    }
]
@Data
public class EventSchema {

    /** トピック */
    public String topic;

    /** サブジェクト */
    public String subject;

    /** イベントタイプ */
    public String eventType;

    /** イベント発生日時 */
    public Date eventTime;

    /** ID */
    public String id;

    /** データのバージョン */
    public String dataVersion;

    /** メタデータのバージョン */
    public String metadataVersion;

    /** データ */
    public Map<String, Object> data;
}

Functionクラスの作成

Functionクラスには、ファンクションごとに行いたい処理を記述する。

// Functionクラス
public class EventGridFunction implements Function<EventSchema, String> {
    public String apply(EventSchema event) {
        return "success";
    }
}

Handlerクラスの作成

Handlerクラスにはトリガーの設定、ファンクションを呼び出す処理を記述する。

// Handlerクラス
public class EventGridHandler extends FunctionInvoker<EventSchema, String> {

    // Functionクラスのbean登録名とHandlerクラスの@FunctionName("eventgrid")の属性に
    // 指定した名前は一致させる
    @FunctionName("eventgrid")
    public void execute(@EventGridTrigger(name = "event") EventSchema event, ExecutionContext context) {
        handleRequest(event, context);
    }
}

トリガーの設定

トリガーの設定はアノテーションで行う。@FunctionName("eventgrid")を付与したメソッドのパラメーターにcom.microsoft.azure.functions.annotation.EventGridTriggerを付与する。
アノテーションの属性については以下の通り。

属性名 説明
name リクエストやリクエストボディのファンクションコードで使用される変数名。必須
dataType パラメータ値をどのように扱うかを定義する。以下の値が設定可能。
"":値を文字列として取得し、POJOにデシリアライズしようとする(デフォルト)
string:常に文字列として値を取得する
binary:値をバイナリデータとして取得し、byte[]にデシリアライズしようとする
// 記述例
public void execute(@EventGridTrigger(name = "event") EventSchema event, ExecutionContext context) {
}

ファンクションを呼び出す処理

O FunctionInvoker<I, O>.handleRequest(I, ExecutionContext)メソッドでファンクションを呼び出すことが出来る。

// 記述例
String response = handleRequest(event, context);

ローカルでの動作確認

EventGrid Triggerの起動には、Azure Blob Storageが必要。
今回は、ローカル環境で使用できるAzure Blob StorageのエミュレータであるAzuriteを使用する例を示す。

Azuriteの導入

コマンドプロンプトで以下のコマンドを実行する。

npm install -g azurite

インストール完了後にc:\\azuriteディレクトリを作成し、以下のコマンドでAzuriteを起動する

azurite --silent --location c:\\azurite --debug c:\\azurite\\debug.log

起動すると以下のようなログが表示される

C:>azurite --silent --location c:\\azurite --debug c:\\azurite\\debug.log
Azurite Blob service is starting at http://127.0.0.1:10000
Azurite Blob service is successfully listening at http://127.0.0.1:10000
Azurite Queue service is starting at http://127.0.0.1:10001
Azurite Queue service is successfully listening at http://127.0.0.1:10001
Azurite Table service is starting at http://127.0.0.1:10002
Azurite Table service is successfully listening at http://127.0.0.1:10002

起動中のAzuriteはCtrl + cで停止できる。

ファンクションの設定

ファンクションプロジェクトのlocal.settings.jsonを開き、AzureWebJobsStorageUseDevelopmentStorage=trueと設定する。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "java",
    "MAIN_CLASS":"jp.co.sample.functions.Application"
  }
}

ファンクションの処理の中でAzureBlobStorageに対して処理を行っている場合、以下の接続設定を利用する。 以下はAzuriteの接続設定である。

設定
アカウントキー Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
アカウント名 devstoreaccount1
Blobエンドポイント http://127.0.0.1:10000/devstoreaccount1

Azurite起動中はMicrosoft Azure Storage Explorerの「ローカルで接続済み」->「ストレージアカウント」->「エミュレーター」で起動中のエミュレータの操作をすることも可能。

ファンクション動作確認

ファンクションの作成完了後にプロジェクトをビルドする。

gradlew azureFunctionsPackage

以下のコマンドでAzuriteを起動する

azurite --silent --location c:\\azurite --debug c:\\azurite\\debug.log

ファンクションを起動する。

gradlew azureFunctionsRun

起動に成功すると以下のようにファンクションの一覧が表示される。

> Task :azureFunctionsRun
Azure Function App's staging directory found at: C:\\pleiades-2021-06\\pleiades\\workspace\\hello-spring-function-azure-gradle\\build\\azure-functions\\java-functions

Azure Functions Core Tools
Core Tools Version:       3.0.3734 Commit hash: 61192bb28820be76916f85209916152801483456  (64-bit)
Function Runtime Version: 3.1.4.0

Functions:

        http: [POST] http://localhost:7071/api/http

        eventgrid: eventGridTrigger

以下のURLにPOSTリクエストを送ることでファンクションをローカルで実行することが出来る。 http://localhost:7071/runtime/webhooks/eventgrid?functionName={ファンクション名} その際ヘッダーに以下の2つを設定する

  • Content-Type:application/json
  • aeg-event-type:Notification

リクエストボディに以下のようなEventGridTriggerイベント情報を貼り付ける

[
    {
        "topic": "/subscriptions/{subscription-id}/resourceGroups/Storage/providers/Microsoft.Storage/storageAccounts/my-storage-account",
        "subject": "/blobServices/default/containers/my-file-system/blobs/new-file.txt",
        "eventType": "Microsoft.Storage.BlobCreated",
        "eventTime": "2017-06-26T18:41:00.9584103Z",
        "id": "831e1650-001e-001b-66ab-eeb76e069631",
        "data": {
            "api": "CreateFile",
            "clientRequestId": "6d79dbfb-0e37-4fc4-981f-442c9ca65760",
            "requestId": "831e1650-001e-001b-66ab-eeb76e000000",
            "eTag": "\\"0x8D4BCC2E4835CD0\\"",
            "contentType": "text/plain",
            "contentLength": 0,
            "contentOffset": 0,
            "blobType": "BlockBlob",
            "url": "http://127.0.0.1:10000/devstoreaccount1/java/test.zip",
            "sequencer": "00000000000004420000000000028963",
            "storageDiagnostics": {
                "batchId": "b68529f3-68cd-4744-baa4-3c0498ec19f0"
            }
        },
        "dataVersion": "2",
        "metadataVersion": "1"
    }
]


他のTriggerの作成に関する記事も書いています。

olafnosuke.hatenablog.com

olafnosuke.hatenablog.com

olafnosuke.hatenablog.com