Edit

Quickstart: Create a Java Durable Functions app

Use Durable Functions, a feature of Azure Functions, to write stateful functions in a serverless environment. Durable Functions manages state, checkpoints, and restarts in your application.

In this quickstart, you create and test a Durable Functions app in Java.

A basic Durable Functions app has three functions:

  • Orchestrator function (Cities): A workflow that orchestrates other functions.
  • Activity function (Capitalize): A function that the orchestrator calls to perform work and return a value.
  • Client function (StartOrchestration): An HTTP-triggered function that starts the orchestrator.

This quickstart offers three setup paths. Use the selector at the top of the page to choose your preferred approach:

  • Manual setup: Create each file by hand for full control over the project structure.
  • Maven command: Use a Maven archetype to scaffold the project in one command.
  • Visual Studio Code: Use the VS Code Azure Functions extension to generate the project through a guided UI.

Prerequisites

To complete this quickstart, you need:

If you don't have an Azure account, create a free account before you begin.

Add required dependencies and plugins to your project

Add the following code to your pom.xml file. Before you copy it, replace your-unique-app-name with a globally unique function app name. Adjust region, javaVersion, and resourceGroup to match your environment.

<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>westus</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>

Add the required JSON files

Add a host.json file to your project directory. It should look similar to the following example:

{
  "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)"
  }
}

Note

Durable Functions for Java requires extension bundle v4. Earlier bundles aren't supported. For more information, see the extension bundles documentation.

Durable Functions needs a storage provider to store runtime state. Add a local.settings.json file to your project directory to configure the storage provider. To use Azure Storage as the provider, set the value of AzureWebJobsStorage to the connection string of your Azure Storage account:

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

Important

The local.settings.json file can contain secrets. Make sure you add it to your .gitignore file to avoid committing it to source control.

Create your Durable Functions orchestrator, activity, and client functions

The following sample code shows a basic example of each type of function:

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();
    }
}

Create a local Durable Functions project by using the Maven command

Run the following command to generate a project that contains the basic functions of a Durable Functions app:

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

At the prompts, provide the following information:

Prompt Action
groupId Enter com.function.
artifactId Enter myDurableFunction.
version Select 1.0-SNAPSHOT.
package Enter com.function.
Y Enter Y and select Enter to confirm.

Now you have a local project that has the three functions that are in a basic Durable Functions app. The archetype includes com.microsoft:durabletask-azure-functions as a dependency in your pom.xml file automatically.

Configure the back-end storage provider for Durable Functions

Durable Functions needs a storage provider to store runtime state. You can set Azure Storage as the storage provider in local.settings.json. Use the connection string of your Azure storage account as the value for AzureWebJobsStorage like in this example:

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

Important

The local.settings.json file can contain secrets. Make sure you add it to your .gitignore file to avoid committing it to source control.

Create your local project

  1. In Visual Studio Code, select F1 (or select Ctrl/Cmd+Shift+P) to open the command palette. At the prompt (>), enter and then select Azure Functions: Create New Project.

    Screenshot of the Azure Functions Create New Project command in the Visual Studio Code command palette.

  2. Select Browse. In the Select Folder dialog, go to a folder to use for your project, and then choose Select.

  3. At the prompts, provide the following information:

    Prompt Action
    Select a language Select Java.
    Select a version of Java Select Java 8 or later. Select the Java version that your functions run on in Azure, and one that you verified locally.
    Provide a group ID Enter com.function.
    Provide an artifact ID Enter myDurableFunction.
    Provide a version Enter 1.0-SNAPSHOT.
    Provide a package name Enter com.function.
    Provide an app name Enter myDurableFunction.
    Select the build tool for Java project Select Maven.
    Select how you would like to open your project Select Open in new window.

You now have a project that has an example HTTP function. You can remove the generated HTTP function, because you add the Durable Functions in the next step.

Add functions to the project

  1. In the command palette, enter and then select Azure Functions: Create Function.

  2. For Change template filter, select All.

  3. At the prompts, provide the following information:

    Prompt Action
    Select a template for your function Select DurableFunctionsOrchestration.
    Provide a package name Enter com.function.
    Provide a function name Enter DurableFunctionsOrchestrator.
  4. In the dialog, choose Select storage account to set up a storage account, and then follow the prompts.

You should now have the three basic functions generated for a Durable Functions app.

Configure pom.xml and host.json for Durable Functions

Add the following dependency to your pom.xml file:

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

Add the extensions property to your host.json file. If the file already has other properties, merge the extensions block into the existing JSON:

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "JavaTestHub"
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.0.0)"
  }
}

Test the function locally

Azure Functions Core Tools gives you the capability to run an Azure Functions project on your local development computer.

  1. If you're using Visual Studio Code, open a new terminal window and run the following commands to build the project:

    mvn clean package
    

    Then, run the durable function:

    mvn azure-functions:run
    
  2. In the terminal panel, copy the URL endpoint of your HTTP-triggered function.

    Screenshot of the terminal output showing the HTTP endpoint URL for the local Azure Functions runtime.

  3. Use your HTTP test tool to send an HTTP POST request to the URL endpoint.

    The response should look similar to the following example:

    {
        "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..."
    }
    

    The response is the HTTP function's initial result. It lets you know that the durable orchestration started successfully. It doesn't yet display the end result of the orchestration. The response includes a few useful URLs. For now, query the status of the orchestration.

  4. Copy the URL value for statusQueryGetUri, paste it in your browser's address bar, and execute the request. Alternatively, you can continue to use the HTTP test tool to issue the GET request.

    The request queries the orchestration instance for the status. You should see that the instance finished and that it includes the outputs or results of the durable function, like in this example:

    {
        "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"
    }