Help us understand the problem. What is going on with this article?

Azure Functions & Java のウォームアップトリガー実装時の注意点

Azure Functions の Premium プランでは ウォームアップトリガー を用いてインスタンスのスケールアウト時に任意のウォームアップ処理を実行できます。Java で実装する際には注意するポイントがありますので、本記事で簡単にまとめたいと思います。

tl;dr

Azure Functions の Java は現状では WarmupTrigger 属性をサポートしていないため、ウォームアップ用の function.json を自前で準備しておき、ビルド成果物のパッケージに同梱する必要があります。

ドキュメントの解説

Azure Functions のウォームアップトリガーについて以下のドキュメントにまとまっています。
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-warmup?tabs=java

以下はドキュメントからの抜粋です。
トリガー - 例 のコードをコピーして自身の Java プログラムに組み込み、run メソッドの中身を任意の処理に書き換える必要があります。

image.png

トリガー - 属性 に記載の通り、WarmupTrigger 属性は現状 C# のみサポートされており、C# スクリプト / JavaScript / Python / Java ではサポートされていません。

image.png

どういうことかと言うと、HttpTrigger 属性を例に説明します。例えば HTTP トリガーの Function を実装する場合、以下ドキュメントのように HttpTrigger のアノテーションを Java のメソッドに付与します。azure-functions-maven-plugin でビルドを実施する際に、自動的に function.json が生成されます。
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-java?tabs=consumption#triggers-and-annotations

image.png

一方で、WarmupTrigger は Java ではサポートされていないため、必要な情報を持つ function.json はビルド時に生成されません。必要な情報というのは トリガー - 構成 に記載された以下の項目群のことです。

image.png

ワークアラウンド

Java でウォームアップトリガーを利用するためには以下の対応が必要です。

  1. @FunctionName("Warmup") アノテーションが付与された Java メソッドを作成
  2. 必要な情報を持つ function.json を作成
  3. function.json をビルド成果物に同梱するよう設定
  4. アプリケーションをビルドして Azure Functions にデプロイ

以下のサンプルコードに沿って説明していきたいと思います。
https://github.com/nakazax/azure-functions-premium-warmup-java

1. @FunctionName("Warmup") アノテーションが付与された Java メソッドを作成

トリガー - 例 をそのまま流用する形で実装しています。run メソッドの中身を任意の処理に書き換えてご利用ください。
https://github.com/nakazax/azure-functions-premium-warmup-java/blob/master/src/main/java/com/functionp/Warmup.java

azure-functions-premium-warmup-java/src/main/java/com/functionp/Function.java
package com.functionp;

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

public class Warmup {

    @FunctionName("Warmup")
    public void run( ExecutionContext context) {
       context.getLogger().info("Function App instance is warm 🌞🌞🌞");
    }
}

2. 必要な情報を持つ function.json を作成

トリガー - 構成 を参考に必要な情報を定義した function.json を作成しておきます。scriptFileentryPoint は自身のアプリケーションに合わせて書き換えて利用ください。
https://github.com/nakazax/azure-functions-premium-warmup-java/blob/master/src/main/resources/Warmup/function.json

azure-functions-premium-warmup-java/src/main/resources/Warmup/function.json
{
  "scriptFile": "../azure-functions-premium-warmup-java-1.0-SNAPSHOT.jar",
  "entryPoint": "com.functionp.Warmup.run",
  "bindings": [ {
    "type": "warmupTrigger",
    "direction": "in",
    "name": "Warmup"
  } ]
}

3. function.json をビルド成果物に同梱するよう設定

先に作成した azure-functions-premium-warmup-java/src/main/resources/Warmup/function.jsonazure-functions-premium-warmup-java/target/azure-functions/${applicatioName}/Warmup に格納するように設定します。

ビルドツールとして Maven を利用している場合は pom.xml の中で当該処理を実装するのが手軽かと思います。以下は pom.xml の抜粋で、<id>copy-warmup-function-json</id> のブロックで当該処理を定義しています。
https://github.com/nakazax/azure-functions-premium-warmup-java/blob/master/pom.xml

azure-functions-premium-warmup-java/pom.xml(抜粋)
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-resources</id>
            <phase>package</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration>
                <overwrite>true</overwrite>
                <outputDirectory>${stagingDirectory}</outputDirectory>
                <resources>
                    <resource>
                        <directory>${project.basedir}</directory>
                        <includes>
                            <include>host.json</include>
                            <include>local.settings.json</include>
                        </includes>
                    </resource>
                </resources>
            </configuration>
        </execution>
        <execution>
            <id>copy-warmup-function-json</id>
            <phase>package</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration>
                <overwrite>true</overwrite>
                <outputDirectory>${stagingDirectory}/Warmup</outputDirectory>
                <resources>
                    <resource>
                        <directory>src/main/resources/Warmup</directory>
                        <includes>
                            <include>function.json</include>
                        </includes>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

4. アプリケーションをビルドして Azure Functions にデプロイ

後はお好みの方法でアプリケーションのビルドと Azure Functions へのデプロイを行います。以下 URL は Azure Pipelines の定義のサンプルです。
https://github.com/nakazax/azure-functions-premium-warmup-java/blob/master/azure-pipelines.yml

デプロイ後の挙動 (正常時)

上記の流れに沿ってデプロイを行った後の Azure リソースの状態は以下のようになるはずです。

Azure Pipelines

ビルド & デプロイともに成功
image.png

デプロイの詳細でエラーメッセージは出ない
image.png

Azure Functions

デプロイ先の Azure Functions
image.png

[デプロイ センター] に「production に正常にデプロイされました」と表示される
image.png

[関数] に Warmup トリガーが表示される
image.png

[関数] > [Warmup] をクリックすると以下のような詳細が表示される
image.png

[ログ] > [traces] を見ると Warmup が実行された旨、表示される
image.png

(参考) 必要な情報を持つ function.json が存在しない場合の挙動

以下は Java のメソッドだけを実装して Azure Functions にデプロイした場合の挙動です。Azure Pipelines でのビルド & デプロイ自体は成功しますが、Azure Functions の [デプロイ センター] に「production にデプロイできませんでした」と表示され、デプロイに失敗します。
(最初、原因が分からずにハマりました。。。)

Azure Pipelines

ビルド & デプロイともに成功
image.png

デプロイの詳細でエラーメッセージは出ない
image.png

Azure Functions

[デプロイ センター] に「production にデプロイできませんでした」と表示される
image.png

[関数] に Warmup トリガーが表示されない
image.png

以上です。

nakazax
Cloud Solution Architect at Microsoft / AWS 11x Certified / Azure 10x Certified / GCP 6x Certified / 中里 浩之
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away