LoginSignup
3
1

More than 3 years have passed since last update.

Java で Azure Functionsの関数を実装する

Last updated at Posted at 2021-04-14

Java で Azure Functionsの関数を実装する

Azure Functions とは、イベントドリブンでプログラムを実行してくれるSaaSプラットフォームです。いわゆるサーバレスプラットフォームと呼ばれるもので、AWS で言うのところの Lambda です(知らないんですけど)

Azure Functionsは、様々な言語とトリガサポートします。

言語では、

  • C#
  • GO
  • Java
  • JavaScript / TypeScript
  • PowerShell
  • Python
  • Rust

トリガ(イベント)では、

  • HTTP
  • タイマー
  • Storage Queue / ServiceBug
  • CosmosDb
  • ...

などです。

詳細は以下のDocsを当たってください。

Azure Functions のドキュメント | Microsoft Docs

Javaからの利用

Azure Functions 用の Maven plugin がリリースされていますので、それを使いましょう。

Maven Plugin for Azure Functions | Microsoft Docs

Functions プロジェクトの生成は、以下の通り mvn から generate します。サポートされている、Javaのバージョンは Java8 or Java11 です。javaVersionに使いたいJavaのバージョンを指定してください。

mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=8mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=8

デフォルトでHTTPトリガーが自動で生成されます。Web APIを実装できます。

    @FunctionName("HttpExample")
    public HttpResponseMessage run(
            @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET, HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        // Parse query parameter
        final String query = request.getQueryParameters().get("name");
        final String name = request.getBody().orElse(query);

        if (name == null) {
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
        } else {
            return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
        }
    }

ローカル実行

ローカルで実行するには、Azure Functions Core Toolsが必要です。Visual Studio Code でプロジェクトを開くと、これらのツールのインストールが促されるのでインストールしてください。手動でもインストールできます。詳細は以下のURLへ。

Azure Functions Core Tools の操作 | Microsoft Docs

インストールが終わると、func というコマンドがパスに通ると思いますが、Javaからはこのコマンドは直接利用せず、mvn経由で実行します。package してから azure-functions:runするようにしてください。

mvn package azure-functions:run

実行されると、以下のようにホストされた関数が表示されます。CURLなど curl http://localhost:7071/api/HttpExample?name=azure でクセスするとレスポンスを取得出来ると思います。

[INFO] Azure Functions Core Tools found.
Azure Functions Core Tools (3.0.2931 Commit hash: d552c6741a37422684f0efab41d541ebad2b2bd2)
Function Runtime Version: 3.0.14492.0
[2021-04-14T06:53:42.928] Worker process started and initialized.

Functions:

        HttpExample: [GET,POST] http://localhost:7071/api/HttpExample

関数の追加

関数の追加もmvn で行います。Java以外の言語は、func コマンドで実行したりもするのですが。

mvn azure-functions:add

対話的に聞かれるので、追加したいトリガーを選択します。

Choose from below options as template for new function
0. HttpTrigger
1. BlobTrigger
2. QueueTrigger
3. TimerTrigger
4. EventGridTrigger
5. EventHubTrigger
6. CosmosDBTrigger
7. ServiceBusQueueTrigger
8. ServiceBusTopicTrigger
Enter index to use: 3
[INFO] Selected function template: TimerTrigger
[INFO] Successfully found function template: TimerTrigger
[INFO]
[INFO] Step 3 of 4: Prepare required parameters
[INFO] Common parameter [Function Name]: name for both the new function and Java class
Enter value for Function Name: TimerTriggerFunction
[INFO] Common parameter [Package Name]: package name of the new Java class
Enter value for Package Name: com.example.moris
[INFO] Trigger specific parameter [schedule]:Enter a cron expression of the format '{second} {minute} {hour} {day} {month} {day of week}' to specify the schedule.
Enter value for schedule(Default: 0 * * * * *):
[INFO]
[INFO] Summary of parameters for function template:
[INFO] schedule: 0 * * * * *
[INFO] functionName: TimerTriggerFunction
[INFO] className: TimerTriggerFunction
[INFO] packageName: com.example.moris
[INFO]
[INFO] Step 4 of 4: Saving function to file
[INFO] Successfully saved new function at c:\p\moris\blog\functions-sample\src\main\java\com\example\moris\TimerTriggerFunction.java
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

デプロイ

WebApps用のプラグインでは config があったのですが、 Functions 用のプラグインにはありません。あらかじめ構成したい場合は、先ほど紹介したDocsをみてconfigurationを追加してください。構成がないままazure-functions:deployすると、適当にAzureリソースが作られます。簡単にテストしたいときは、これで問題ないでしょう。以下がデプロイしたときに自動で生成されたものです。

                <configuration>
                    <!-- function app name -->
                    <appName>${functionAppName}</appName>
                    <!-- function app resource group -->
                    <resourceGroup>java-functions-group</resourceGroup>
                    <!-- function app service plan name -->
                    <appServicePlanName>java-functions-app-service-plan</appServicePlanName>
                    <!-- function app region-->
                    <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-regions for all valid values -->
                    <region>westus</region>
                    <!-- function pricingTier, default to be consumption if not specified -->
                    <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-pricing-tiers for all valid values -->
                    <!-- <pricingTier></pricingTier> -->

                    <!-- Whether to disable application insights, default is false -->
                    <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details for all valid configurations for application insights-->
                    <!-- <disableAppInsights></disableAppInsights> -->
                    <runtime>
                        <!-- runtime os, could be windows, linux or docker-->
                        <os>windows</os>
                        <javaVersion>8</javaVersion>
                        <!-- for docker function, please set the following parameters -->
                        <!-- <image>[hub-user/]repo-name[:tag]</image> -->
                        <!-- <serverId></serverId> -->
                        <!-- <registryUrl></registryUrl>  -->
                    </runtime>
                    <appSettings>
                        <property>
                            <name>FUNCTIONS_EXTENSION_VERSION</name>
                            <value>~3</value>
                        </property>
                    </appSettings>
                </configuration>

デプロイする前には、正しくパッケージングしましょう。細かな話を言うと、azure-functions:package がパッケージングのゴールですが、シンプルにpackage で、必要なJSONファイルなどを生成してくれます。target/azure-functions が デプロイ用の成果物が格納されたディレクトリになります。各トリガの情報は、functions.json に自動生成されます。

{
  "scriptFile" : "../functions-sample-1.0-SNAPSHOT.jar",
  "entryPoint" : "com.example.moris.Function.run",
  "bindings" : [ {
    "type" : "httpTrigger",
    "direction" : "in",
    "name" : "req",
    "methods" : [ "GET", "POST" ],
    "authLevel" : "ANONYMOUS"
  }, {
    "type" : "http",
    "direction" : "out",
    "name" : "$return"
  } ]
}

デプロイはするには、以下のコマンドを実行します。あらかじめ、az login しておいてください。

mvn azure-functions:deploy

ワーカーやライブラリの依存関係の話

トリガーを具体的に呼び出すのは Azure Functions Java Worker です。ソースはGithubで公開されています。Java Functions 上での怪しい挙動などは、ここにIssueを投げても良いでしょう(サポートでもいいですけど)

また、Java8とJava11で、クラスロードの優先順位が変わるので注意が必要です。

Java8では、ワーカー側のJarを読み込んで、次にクライアント側のJarを読み込みますが、Java11では、常にクライアント側のJarを読み込みます。Java8でこの挙動を変更したいときは、環境変数 FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS1 or True に設定してください。

とくに、FunctionsのランタイムにJava8を選択したとき、 Azure SDK for Java との相性が悪いので 例外が出たり、ハングしてタイムアウトする場合があるので注意が必要です。

まとめ

WebApps のほうは、azure-webapp なのに、Functions の方は、azure-functions でいつもプラグイン名が混乱します。単複系は難しい。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1