快速入门:创建 Java Durable Functions 应用

使用 Durable Functions(Azure Functions 的一项功能)在无服务器环境中编写有状态函数。 Durable Functions 管理应用程序中的状态、检查点和重启。

在本快速入门中,你将在 Java 中创建和测试“hello world”Durable Functions 应用。

最基本的 Durable Functions 应用包含三个函数:

  • 业务流程协调程序函数:用于协调其他函数的工作流
  • 活动函数:由业务流程协调程序函数调用的函数,它会执行工作并选择性地返回一个值
  • 客户端函数:Azure 中用于启动业务流程协调程序函数的常规函数。 本示例使用 HTTP 触发的函数。

本快速入门介绍了创建此“hello world”应用的不同方法。 使用页面顶部的选择器设置首选方法。

先决条件

若要完成本快速入门,你需要:

  • 已安装 Java 开发人员工具包版本 8 或更高版本。

  • 已安装 Apache Maven 版本 3.0 或更高版本。

  • 最新版本的 Azure Functions Core Tools

    对于 Azure Functions 4.x,需要 Core Tools 版本 4.0.4915 或更高版本

  • 一个可以保证数据安全的 HTTP 测试工具。 有关详细信息,请参阅 HTTP 测试工具

  • Azure 订阅。 若要使用 Durable Functions,必须具有 Azure 存储帐户。

如果没有 Azure 订阅,可在开始前创建一个试用帐户

向项目添加所需的依赖项和插件

将以下代码添加到 pom.xml 文件中:

<properties>
  <azure.functions.maven.plugin.version>1.18.0</azure.functions.maven.plugin.version>
  <azure.functions.java.library.version>3.0.0</azure.functions.java.library.version>
  <durabletask.azure.functions>1.0.0</durabletask.azure.functions>
  <functionAppName>your-unique-app-name</functionAppName>
</properties>

<dependencies>
  <dependency>
    <groupId>com.microsoft.azure.functions</groupId>
    <artifactId>azure-functions-java-library</artifactId>
    <version>${azure.functions.java.library.version}</version>
  </dependency>
  <dependency>
    <groupId>com.microsoft</groupId>
    <artifactId>durabletask-azure-functions</artifactId>
    <version>${durabletask.azure.functions}</version>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.8.1</version>
    </plugin>
    <plugin>
      <groupId>com.microsoft.azure</groupId>
      <artifactId>azure-functions-maven-plugin</artifactId>
      <version>${azure.functions.maven.plugin.version}</version>
      <configuration>
        <appName>${functionAppName}</appName>
        <resourceGroup>java-functions-group</resourceGroup>
        <appServicePlanName>java-functions-app-service-plan</appServicePlanName>
        <region>chinanorth2</region>
        <runtime>
          <os>windows</os>
          <javaVersion>11</javaVersion>
        </runtime>
        <appSettings>
          <property>
            <name>FUNCTIONS_EXTENSION_VERSION</name>
            <value>~4</value>
          </property>
        </appSettings>
      </configuration>
      <executions>
        <execution>
          <id>package-functions</id>
          <goals>
            <goal>package</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    <plugin>
      <artifactId>maven-clean-plugin</artifactId>
      <version>3.1.0</version>
    </plugin>
  </plugins>
</build>

添加所需的 JSON 文件

将 host.json 文件添加到项目目录。 它应如以下示例所示:

{
  "version": "2.0",
  "logging": {
    "logLevel": {
      "DurableTask.AzureStorage": "Warning",
      "DurableTask.Core": "Warning"
    }
  },
  "extensions": {
    "durableTask": {
      "hubName": "JavaTestHub"
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.0.0)"
  }
}

注意

请务必注意,目前只有 Azure Functions v4 扩展捆绑包具有对 Durable Functions for Java 的必要支持。 v3 和早期扩展捆绑包不支持 Durable Functions for Java。 有关扩展捆绑包的详细信息,请参阅扩展捆绑包文档

Durable Functions 需要存储提供程序来存储运行时状态。 将 local.settings.json 文件添加到项目目录以配置存储提供程序。 若要使用 Azure 存储作为提供程序,请将 AzureWebJobsStorage 值设置为 Azure 存储帐户的连接字符串:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "<your storage account connection string>",
    "FUNCTIONS_WORKER_RUNTIME": "java"
  }
}

创建自己的函数

以下示例代码显示了每种函数类型的基本示例:

import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.*;
import java.util.*;

import com.microsoft.durabletask.*;
import com.microsoft.durabletask.azurefunctions.DurableActivityTrigger;
import com.microsoft.durabletask.azurefunctions.DurableClientContext;
import com.microsoft.durabletask.azurefunctions.DurableClientInput;
import com.microsoft.durabletask.azurefunctions.DurableOrchestrationTrigger;

public class DurableFunctionsSample {
    /**
     * This HTTP-triggered function starts the orchestration.
     */
    @FunctionName("StartOrchestration")
    public HttpResponseMessage startOrchestration(
            @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
            @DurableClientInput(name = "durableContext") DurableClientContext durableContext,
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        DurableTaskClient client = durableContext.getClient();
        String instanceId = client.scheduleNewOrchestrationInstance("Cities");
        context.getLogger().info("Created new Java orchestration with instance ID = " + instanceId);
        return durableContext.createCheckStatusResponse(request, instanceId);
    }

    /**
     * This is the orchestrator function, which can schedule activity functions, create durable timers,
     * or wait for external events in a way that's completely fault-tolerant.
     */
    @FunctionName("Cities")
    public String citiesOrchestrator(
            @DurableOrchestrationTrigger(name = "taskOrchestrationContext") TaskOrchestrationContext ctx) {
        String result = "";
        result += ctx.callActivity("Capitalize", "Tokyo", String.class).await() + ", ";
        result += ctx.callActivity("Capitalize", "London", String.class).await() + ", ";
        result += ctx.callActivity("Capitalize", "Seattle", String.class).await() + ", ";
        result += ctx.callActivity("Capitalize", "Austin", String.class).await();
        return result;
    }

    /**
     * This is the activity function that is invoked by the orchestrator function.
     */
    @FunctionName("Capitalize")
    public String capitalize(@DurableActivityTrigger(name = "name") String name, final ExecutionContext context) {
        context.getLogger().info("Capitalizing: " + name);
        return name.toUpperCase();
    }
}

使用 Maven 命令创建本地项目

运行以下命令,生成一个包含 Durable Functions 应用的基本函数的项目:

mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DarchetypeVersion=1.51 -Dtrigger=durablefunctions

根据提示提供以下信息:

Prompt 操作
groupId 输入 com.function
artifactId 输入 myDurableFunction
version 选择 1.0-SNAPSHOT
package 输入 com.function
Y 输入 Y,然后选择 Enter 键进行确认。

现在,你有一个本地项目,其中包含基本 Durable Functions 应用中的三个函数。

检查以确保 com.microsoft:durabletask-azure-functions 设置为 pom.xml 文件中的依赖项。

配置后端存储提供程序

Durable Functions 需要存储提供程序来存储运行时状态。 可以在 local.settings.json 中将 Azure 存储设置为存储提供程序。 使用 Azure 存储帐户的连接字符串作为 AzureWebJobsStorage 的值,如以下示例所示:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "<your storage account connection string>",
    "FUNCTIONS_WORKER_RUNTIME": "java"
  }
}

创建本地项目

  1. 在 Visual Studio Code 中,选择 F1(或选择 Ctrl/Cmd+Shift+P)以打开命令面板。 在提示符 (>) 处,输入内容,然后选择“Azure Functions: 创建新项目”

    创建新函数项目命令的屏幕截图。

  2. 选择浏览。 在“选择文件夹”对话框中,转到要用于项目的文件夹,然后选择“选择”

  3. 根据提示提供以下信息:

    Prompt 操作
    选择一种语言 选择“Java”
    选择一个 Java 版本 选择 Java 8 或更高版本。 在 Azure 中选择运行函数的 Java 版本,然后选择在本地验证的 Java 版本。
    提供一个组 ID 输入 com.function
    提供一个项目 ID 输入 myDurableFunction
    提供一个版本 输入 1.0-SNAPSHOT
    提供一个包名称 输入 com.function
    提供一个应用名称 输入 myDurableFunction
    选择 Java 项目的生成工具 选择“Maven”。
    选择打开项目的方式 选择“在新窗口中打开”

现在,你有一个包含示例 HTTP 函数的项目。 如果你愿意,可以删除此函数,因为你将在下一步中添加 Durable Functions 应用的基本函数。

向项目添加函数

  1. 在命令面板中,输入内容,然后选择“Azure Functions: 创建函数”

  2. 对于“更改模板筛选器”,请选择“全部”

  3. 根据提示提供以下信息:

    Prompt 操作
    选择函数的模板 选择“DurableFunctionsOrchestration”
    提供一个包名称 输入 com.function
    提供函数名称 输入 DurableFunctionsOrchestrator
  4. 在对话框中,选择“选择存储帐户”设置存储帐户,然后按照提示进行操作。

现在,应该为 Durable Functions 应用生成了三个基本函数。

配置 pom.xml 和 host.json

将以下依赖项添加到 pom.xml 文件:

<dependency>
  <groupId>com.microsoft</groupId>
  <artifactId>durabletask-azure-functions</artifactId>
  <version>1.0.0</version>
</dependency>

extensions 属性添加到 host.json 文件:

"extensions": { "durableTask": { "hubName": "JavaTestHub" }}

在本地测试函数

使用 Azure Functions Core Tools,你能够在本地开发计算机上运行 Azure Functions 项目。

注意

Durable Functions for Java 需要 Azure Functions Core Tools 版本 4.0.4915 或更高版本。 可以通过在终端中运行 func --version 命令来查看已安装的版本。

  1. 如果使用的是 Visual Studio Code,请打开新的终端窗口,并运行以下命令来生成项目:

    mvn clean package
    

    然后,运行持久函数:

    mvn azure-functions:run
    
  2. 在终端面板中,复制 HTTP 触发的函数的 URL 终结点。

    Azure 本地输出的屏幕截图。

  3. 使用 HTTP 测试工具向 URL 终结点发送 HTTP POST 请求。

    响应应当类似于以下示例:

    {
        "id": "d1b33a60-333f-4d6e-9ade-17a7020562a9",
        "purgeHistoryDeleteUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d1b33a60-333f-4d6e-9ade-17a7020562a9?code=ACCupah_QfGKo...",
        "sendEventPostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d1b33a60-333f-4d6e-9ade-17a7020562a9/raiseEvent/{eventName}?code=ACCupah_QfGKo...",
        "statusQueryGetUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d1b33a60-333f-4d6e-9ade-17a7020562a9?code=ACCupah_QfGKo...",
        "terminatePostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d1b33a60-333f-4d6e-9ade-17a7020562a9/terminate?reason={text}&code=ACCupah_QfGKo..."
    }
    

    响应是 HTTP 函数的初始结果。 它让你知道持久业务流程已成功启动。 它尚未显示业务流程的最终结果。 响应中包括了几个有用的 URL。 现在,查询业务流程的状态。

  4. 复制 statusQueryGetUri 的 URL 值,将其粘贴到浏览器的地址栏中,然后执行请求。 或者,可继续使用 HTTP 测试工具发出 GET 请求。

    请求将查询业务流程实例的状态。 应该会看到实例已完成,并且它包含持久函数的输出或结果,如以下示例所示:

    {
        "name": "Cities",
        "instanceId": "d1b33a60-333f-4d6e-9ade-17a7020562a9",
        "runtimeStatus": "Completed",
        "input": null,
        "customStatus": "",
        "output":"TOKYO, LONDON, SEATTLE, AUSTIN",
        "createdTime": "2022-12-12T05:00:02Z",
        "lastUpdatedTime": "2022-12-12T05:00:06Z"
    }