mirror of https://github.com/dapr/java-sdk.git
Merge branch 'master' into dependabot/maven/dapr-spring/ch.qos.logback-logback-core-1.5.13
Signed-off-by: artur-ciocanu <artur.ciocanu@gmail.com>
This commit is contained in:
commit
ee7c230ae9
|
|
@ -54,7 +54,48 @@ This section describes the guidelines for contributing code / docs to Dapr.
|
|||
### Things to consider when adding new API to SDK
|
||||
|
||||
1. All the new API's go under [dapr-sdk maven package](https://github.com/dapr/java-sdk/tree/master/sdk)
|
||||
2. Make sure there is an example talking about how to use the API along with a README. [Example](https://github.com/dapr/java-sdk/pull/1235/files#diff-69ed756c4c01fd5fa884aac030dccb8f3f4d4fefa0dc330862d55a6f87b34a14)
|
||||
2. Make sure there is an example talking about how to use the API along with a README with mechanical markdown. [Example](https://github.com/dapr/java-sdk/pull/1235/files#diff-69ed756c4c01fd5fa884aac030dccb8f3f4d4fefa0dc330862d55a6f87b34a14)
|
||||
|
||||
#### Mechanical Markdown
|
||||
|
||||
Mechanical markdown is used to validate example outputs in our CI pipeline. It ensures that the expected output in README files matches the actual output when running the examples. This helps maintain example output, catches any unintended changes in example behavior, and regressions.
|
||||
|
||||
To test mechanical markdown locally:
|
||||
|
||||
1. Install the package:
|
||||
```bash
|
||||
pip3 install mechanical-markdown
|
||||
```
|
||||
|
||||
2. Run the test from the respective examples README directory, for example:
|
||||
```bash
|
||||
cd examples
|
||||
mm.py ./src/main/java/io/dapr/examples/workflows/README.md
|
||||
```
|
||||
|
||||
The test will:
|
||||
- Parse the STEP markers in the README
|
||||
- Execute the commands specified in the markers
|
||||
- Compare the actual output with the expected output
|
||||
- Report any mismatches
|
||||
|
||||
When writing STEP markers:
|
||||
- Use `output_match_mode: substring` for flexible matching
|
||||
- Quote strings containing special YAML characters (like `:`, `*`, `'`)
|
||||
- Set appropriate timeouts for long-running examples
|
||||
|
||||
Example STEP marker:
|
||||
```yaml
|
||||
<!-- STEP
|
||||
name: Run example
|
||||
output_match_mode: substring
|
||||
expected_stdout_lines:
|
||||
- "Starting workflow: io.dapr.examples.workflows.compensation.BookTripWorkflow"
|
||||
...
|
||||
background: true
|
||||
timeout_seconds: 60
|
||||
-->
|
||||
```
|
||||
|
||||
### Pull Requests
|
||||
|
||||
|
|
|
|||
|
|
@ -18,19 +18,20 @@
|
|||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-data</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-actors</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-messaging</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-workflows</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
@ -71,9 +72,20 @@
|
|||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>testcontainers-dapr</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
|
|
|||
|
|
@ -23,12 +23,10 @@
|
|||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-tests</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>testcontainers-dapr</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
|
|
|||
|
|
@ -23,27 +23,22 @@
|
|||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-springboot</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-autoconfigure</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-data</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-messaging</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-workflows</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-autoconfigure</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
|
|
@ -38,7 +37,6 @@
|
|||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>testcontainers-dapr</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@
|
|||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-keyvalue</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,17 @@
|
|||
<description>Dapr Spring Messaging</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
|||
|
|
@ -15,10 +15,17 @@
|
|||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-workflows</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -28,12 +28,14 @@
|
|||
</modules>
|
||||
|
||||
<properties>
|
||||
<springboot.version>3.2.6</springboot.version>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
<testcontainers.version>1.19.8</testcontainers.version>
|
||||
<junit.version>5.10.2</junit.version>
|
||||
<junit.version>5.11.2</junit.version>
|
||||
<dapr.spring.version>0.16.0-SNAPSHOT</dapr.spring.version>
|
||||
<springboot.version>3.2.6</springboot.version>
|
||||
<springframework.version>6.1.14</springframework.version>
|
||||
<logback-core.version>1.5.13</logback-core.version>
|
||||
</properties>
|
||||
|
||||
|
|
@ -44,43 +46,7 @@
|
|||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback-core.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Dapr dependencies -->
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk</artifactId>
|
||||
|
|
@ -91,33 +57,118 @@
|
|||
<artifactId>dapr-sdk-actors</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-workflows</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-data</artifactId>
|
||||
<version>${dapr.spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-messaging</artifactId>
|
||||
<version>${dapr.spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-workflows</artifactId>
|
||||
<version>${dapr.spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-autoconfigure</artifactId>
|
||||
<version>${dapr.spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-springboot</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>${springframework.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<optional>true</optional>
|
||||
<version>${springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure-processor</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-tests</artifactId>
|
||||
<version>${dapr.spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback-core.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
type: docs
|
||||
title: "AI"
|
||||
linkTitle: "AI"
|
||||
weight: 3000
|
||||
description: With the Dapr Conversation AI package, you can interact with the Dapr AI workloads from a Java application. To get started, walk through the [Dapr AI]({{< ref java-ai-howto.md >}}) how-to guide.
|
||||
---
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
---
|
||||
type: docs
|
||||
title: "How to: Author and manage Dapr Conversation AI in the Java SDK"
|
||||
linkTitle: "How to: Author and manage Conversation AI"
|
||||
weight: 20000
|
||||
description: How to get up and running with Conversation AI using the Dapr Java SDK
|
||||
---
|
||||
|
||||
As part of this demonstration, we will look at how to use the Conversation API to converse with a Large Language Model (LLM). The API
|
||||
will return the response from the LLM for the given prompt. With the [provided conversation ai example](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/conversation), you will:
|
||||
|
||||
- You will provide a prompt using the [Conversation AI example](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/conversation/DemoConversationAI.java)
|
||||
- Filter out Personally identifiable information (PII).
|
||||
|
||||
This example uses the default configuration from `dapr init` in [self-hosted mode](https://github.com/dapr/cli#install-dapr-on-your-local-machine-self-hosted).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started).
|
||||
- Java JDK 11 (or greater):
|
||||
- [Oracle JDK](https://www.oracle.com/java/technologies/downloads), or
|
||||
- OpenJDK
|
||||
- [Apache Maven](https://maven.apache.org/install.html), version 3.x.
|
||||
- [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||
|
||||
## Set up the environment
|
||||
|
||||
Clone the [Java SDK repo](https://github.com/dapr/java-sdk) and navigate into it.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/dapr/java-sdk.git
|
||||
cd java-sdk
|
||||
```
|
||||
|
||||
Run the following command to install the requirements for running the Conversation AI example with the Dapr Java SDK.
|
||||
|
||||
```bash
|
||||
mvn clean install -DskipTests
|
||||
```
|
||||
|
||||
From the Java SDK root directory, navigate to the examples' directory.
|
||||
|
||||
```bash
|
||||
cd examples
|
||||
```
|
||||
|
||||
Run the Dapr sidecar.
|
||||
|
||||
```sh
|
||||
dapr run --app-id conversationapp --dapr-grpc-port 51439 --dapr-http-port 3500 --app-port 8080
|
||||
```
|
||||
|
||||
> Now, Dapr is listening for HTTP requests at `http://localhost:3500` and gRPC requests at `http://localhost:51439`.
|
||||
|
||||
## Send a prompt with Personally identifiable information (PII) to the Conversation AI API
|
||||
|
||||
In the `DemoConversationAI` there are steps to send a prompt using the `converse` method under the `DaprPreviewClient`.
|
||||
|
||||
```java
|
||||
public class DemoConversationAI {
|
||||
/**
|
||||
* The main method to start the client.
|
||||
*
|
||||
* @param args Input arguments (unused).
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try (DaprPreviewClient client = new DaprClientBuilder().buildPreviewClient()) {
|
||||
System.out.println("Sending the following input to LLM: Hello How are you? This is the my number 672-123-4567");
|
||||
|
||||
ConversationInput daprConversationInput = new ConversationInput("Hello How are you? "
|
||||
+ "This is the my number 672-123-4567");
|
||||
|
||||
// Component name is the name provided in the metadata block of the conversation.yaml file.
|
||||
Mono<ConversationResponse> responseMono = client.converse(new ConversationRequest("echo",
|
||||
List.of(daprConversationInput))
|
||||
.setContextId("contextId")
|
||||
.setScrubPii(true).setTemperature(1.1d));
|
||||
ConversationResponse response = responseMono.block();
|
||||
System.out.printf("Conversation output: %s", response.getConversationOutputs().get(0).getResult());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Run the `DemoConversationAI` with the following command.
|
||||
|
||||
```sh
|
||||
java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.conversation.DemoConversationAI
|
||||
```
|
||||
|
||||
### Sample output
|
||||
```
|
||||
== APP == Conversation output: Hello How are you? This is the my number <ISBN>
|
||||
```
|
||||
|
||||
As shown in the output, the number sent to the API is obfuscated and returned in the form of <ISBN>.
|
||||
The example above uses an ["echo"](https://docs.dapr.io/developing-applications/building-blocks/conversation/howto-conversation-layer/#set-up-the-conversation-component)
|
||||
component for testing, which simply returns the input message.
|
||||
When integrated with LLMs like OpenAI or Claude, you’ll receive meaningful responses instead of echoed input.
|
||||
|
||||
## Next steps
|
||||
- [Learn more about Conversation AI]({{< ref conversation-overview.md >}})
|
||||
- [Conversation AI API reference]({{< ref conversation_api.md >}})
|
||||
|
|
@ -38,7 +38,7 @@ Run the following command to install the requirements for running the jobs examp
|
|||
mvn clean install -DskipTests
|
||||
```
|
||||
|
||||
From the Java SDK root directory, navigate to the Dapr Jobs example.
|
||||
From the Java SDK root directory, navigate to the examples' directory.
|
||||
|
||||
```bash
|
||||
cd examples
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ Those examples contain the following workflow patterns:
|
|||
2. [Fan-out/Fan-in Pattern](#fan-outfan-in-pattern)
|
||||
3. [Continue As New Pattern](#continue-as-new-pattern)
|
||||
4. [External Event Pattern](#external-event-pattern)
|
||||
5. [child-workflow Pattern](#child-workflow-pattern)
|
||||
5. [Child-workflow Pattern](#child-workflow-pattern)
|
||||
6. [Compensation Pattern](#compensation-pattern)
|
||||
|
||||
### Chaining Pattern
|
||||
In the chaining pattern, a sequence of activities executes in a specific order.
|
||||
|
|
@ -353,7 +354,7 @@ dapr run --app-id demoworkflowworker --resources-path ./components/workflows --
|
|||
```
|
||||
```sh
|
||||
java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.continueasnew.DemoContinueAsNewClient
|
||||
````
|
||||
```
|
||||
|
||||
You will see the logs from worker showing the `CleanUpActivity` is invoked every 10 seconds after previous one is finished:
|
||||
```text
|
||||
|
|
@ -444,7 +445,7 @@ Started a new external-event model workflow with instance ID: 23410d96-1afe-4698
|
|||
workflow instance with ID: 23410d96-1afe-4698-9fcd-c01c1e0db255 completed.
|
||||
```
|
||||
|
||||
### child-workflow Pattern
|
||||
### Child-workflow Pattern
|
||||
The child-workflow pattern allows you to call a workflow from another workflow.
|
||||
|
||||
The `DemoWorkflow` class defines the workflow. It calls a child-workflow `DemoChildWorkflow` to do the work. See the code snippet below:
|
||||
|
|
@ -540,3 +541,115 @@ The log from client:
|
|||
Started a new child-workflow model workflow with instance ID: c2fb9c83-435b-4b55-bdf1-833b39366cfb
|
||||
workflow instance with ID: c2fb9c83-435b-4b55-bdf1-833b39366cfb completed with result: !wolfkroW rpaD olleH
|
||||
```
|
||||
|
||||
### Compensation Pattern
|
||||
The compensation pattern is used to "undo" or "roll back" previously completed steps if a later step fails. This pattern is particularly useful in scenarios where you need to ensure that all resources are properly cleaned up even if the process fails.
|
||||
|
||||
The example simulates a trip booking workflow that books a flight, hotel, and car. If any step fails, the workflow will automatically compensate (cancel) the previously completed bookings in reverse order.
|
||||
|
||||
The `BookTripWorkflow` class defines the workflow. It orchestrates the booking process and handles compensation if any step fails. See the code snippet below:
|
||||
```java
|
||||
public class BookTripWorkflow extends Workflow {
|
||||
@Override
|
||||
public WorkflowStub create() {
|
||||
return ctx -> {
|
||||
List<String> compensations = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// Book flight
|
||||
String flightResult = ctx.callActivity(BookFlightActivity.class.getName(), String.class).await();
|
||||
ctx.getLogger().info("Flight booking completed: " + flightResult);
|
||||
compensations.add(CancelFlightActivity.class.getName());
|
||||
|
||||
// Book hotel
|
||||
String hotelResult = ctx.callActivity(BookHotelActivity.class.getName(), String.class).await();
|
||||
ctx.getLogger().info("Hotel booking completed: " + hotelResult);
|
||||
compensations.add(CancelHotelActivity.class.getName());
|
||||
|
||||
// Book car
|
||||
String carResult = ctx.callActivity(BookCarActivity.class.getName(), String.class).await();
|
||||
ctx.getLogger().info("Car booking completed: " + carResult);
|
||||
compensations.add(CancelCarActivity.class.getName());
|
||||
|
||||
} catch (Exception e) {
|
||||
ctx.getLogger().info("******** executing compensation logic ********");
|
||||
// Execute compensations in reverse order
|
||||
Collections.reverse(compensations);
|
||||
for (String compensation : compensations) {
|
||||
try {
|
||||
ctx.callActivity(compensation, String.class).await();
|
||||
} catch (Exception ex) {
|
||||
ctx.getLogger().error("Error during compensation: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
ctx.complete("Workflow failed, compensation applied");
|
||||
return;
|
||||
}
|
||||
ctx.complete("All bookings completed successfully");
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each activity class (`BookFlightActivity`, `BookHotelActivity`, `BookCarActivity`) implements the booking logic, while their corresponding compensation activities (`CancelFlightActivity`, `CancelHotelActivity`, `CancelCarActivity`) implement the cancellation logic.
|
||||
|
||||
<!-- STEP
|
||||
name: Run Compensation Pattern workflow worker
|
||||
match_order: none
|
||||
output_match_mode: substring
|
||||
expected_stdout_lines:
|
||||
- "Registered Workflow: BookTripWorkflow"
|
||||
- "Registered Activity: BookFlightActivity"
|
||||
- "Registered Activity: CancelFlightActivity"
|
||||
- "Registered Activity: BookHotelActivity"
|
||||
- "Registered Activity: CancelHotelActivity"
|
||||
- "Registered Activity: BookCarActivity"
|
||||
- "Registered Activity: CancelCarActivity"
|
||||
- "Successfully built dapr workflow runtime"
|
||||
- "Start workflow runtime"
|
||||
- "Durable Task worker is connecting to sidecar at 127.0.0.1:50001."
|
||||
|
||||
- "Starting Workflow: io.dapr.examples.workflows.compensation.BookTripWorkflow"
|
||||
- "Starting Activity: io.dapr.examples.workflows.compensation.BookFlightActivity"
|
||||
- "Activity completed with result: Flight booked successfully"
|
||||
- "Flight booking completed: Flight booked successfully"
|
||||
- "Starting Activity: io.dapr.examples.workflows.compensation.BookHotelActivity"
|
||||
- "Simulating hotel booking process..."
|
||||
- "Activity completed with result: Hotel booked successfully"
|
||||
- "Hotel booking completed: Hotel booked successfully"
|
||||
- "Starting Activity: io.dapr.examples.workflows.compensation.BookCarActivity"
|
||||
- "Forcing Failure to trigger compensation for activity: io.dapr.examples.workflows.compensation.BookCarActivity"
|
||||
- "******** executing compensation logic ********"
|
||||
- "Activity failed: Task 'io.dapr.examples.workflows.compensation.BookCarActivity' (#2) failed with an unhandled exception: Failed to book car"
|
||||
- "Starting Activity: io.dapr.examples.workflows.compensation.CancelHotelActivity"
|
||||
- "Activity completed with result: Hotel canceled successfully"
|
||||
- "Starting Activity: io.dapr.examples.workflows.compensation.CancelFlightActivity"
|
||||
- "Activity completed with result: Flight canceled successfully"
|
||||
background: true
|
||||
sleep: 60
|
||||
timeout_seconds: 60
|
||||
-->
|
||||
|
||||
Execute the following script in order to run the BookTripWorker:
|
||||
```sh
|
||||
dapr run --app-id book-trip-worker --resources-path ./components/workflows --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.compensation.BookTripWorker
|
||||
```
|
||||
|
||||
Once running, execute the following script to run the BookTripClient:
|
||||
```sh
|
||||
java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.compensation.BookTripClient
|
||||
```
|
||||
<!-- END_STEP -->
|
||||
|
||||
The output demonstrates:
|
||||
1. The workflow starts and successfully books a flight
|
||||
2. Then successfully books a hotel
|
||||
3. When attempting to book a car, it fails (intentionally)
|
||||
4. The compensation logic triggers, canceling the hotel and flight in reverse order
|
||||
5. The workflow completes with a status indicating the compensation was applied
|
||||
|
||||
Key Points:
|
||||
1. Each successful booking step adds its compensation action to an ArrayList
|
||||
2. If an error occurs, the list of compensations is reversed and executed in reverse order
|
||||
3. The workflow ensures that all resources are properly cleaned up even if the process fails
|
||||
4. Each activity simulates work with a short delay for demonstration purposes
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.workflows.WorkflowActivity;
|
||||
import io.dapr.workflows.WorkflowActivityContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BookCarActivity implements WorkflowActivity {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BookCarActivity.class);
|
||||
|
||||
@Override
|
||||
public String run(WorkflowActivityContext ctx) {
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
|
||||
// Simulate work
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
logger.info("Forcing Failure to trigger compensation for activity: " + ctx.getName());
|
||||
|
||||
// force the compensation
|
||||
throw new RuntimeException("Failed to book car");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.workflows.WorkflowActivity;
|
||||
import io.dapr.workflows.WorkflowActivityContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BookFlightActivity implements WorkflowActivity {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BookFlightActivity.class);
|
||||
|
||||
@Override
|
||||
public String run(WorkflowActivityContext ctx) {
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
|
||||
// Simulate work
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String result = "Flight booked successfully";
|
||||
logger.info("Activity completed with result: " + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.workflows.WorkflowActivity;
|
||||
import io.dapr.workflows.WorkflowActivityContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BookHotelActivity implements WorkflowActivity {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BookHotelActivity.class);
|
||||
|
||||
@Override
|
||||
public String run(WorkflowActivityContext ctx) {
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
logger.info("Simulating hotel booking process...");
|
||||
|
||||
// Simulate some work
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
String result = "Hotel booked successfully";
|
||||
logger.info("Activity completed with result: " + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.workflows.client.DaprWorkflowClient;
|
||||
import io.dapr.workflows.client.WorkflowInstanceStatus;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class BookTripClient {
|
||||
public static void main(String[] args) {
|
||||
try (DaprWorkflowClient client = new DaprWorkflowClient()) {
|
||||
String instanceId = client.scheduleNewWorkflow(BookTripWorkflow.class);
|
||||
System.out.printf("Started a new trip booking workflow with instance ID: %s%n", instanceId);
|
||||
|
||||
WorkflowInstanceStatus status = client.waitForInstanceCompletion(instanceId, Duration.ofMinutes(30), true);
|
||||
System.out.printf("Workflow instance with ID: %s completed with status: %s%n", instanceId, status);
|
||||
System.out.printf("Workflow output: %s%n", status.getSerializedOutput());
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.workflows.runtime.WorkflowRuntime;
|
||||
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
|
||||
|
||||
public class BookTripWorker {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Register the Workflow with the builder
|
||||
WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder()
|
||||
.registerWorkflow(BookTripWorkflow.class)
|
||||
.registerActivity(BookFlightActivity.class)
|
||||
.registerActivity(CancelFlightActivity.class)
|
||||
.registerActivity(BookHotelActivity.class)
|
||||
.registerActivity(CancelHotelActivity.class)
|
||||
.registerActivity(BookCarActivity.class)
|
||||
.registerActivity(CancelCarActivity.class);
|
||||
|
||||
// Build and start the workflow runtime
|
||||
try (WorkflowRuntime runtime = builder.build()) {
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.durabletask.TaskFailedException;
|
||||
import io.dapr.workflows.Workflow;
|
||||
import io.dapr.workflows.WorkflowStub;
|
||||
import io.dapr.workflows.WorkflowTaskOptions;
|
||||
import io.dapr.workflows.WorkflowTaskRetryPolicy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.time.Duration;
|
||||
|
||||
public class BookTripWorkflow implements Workflow {
|
||||
@Override
|
||||
public WorkflowStub create() {
|
||||
return ctx -> {
|
||||
ctx.getLogger().info("Starting Workflow: " + ctx.getName());
|
||||
List<String> compensations = new ArrayList<>();
|
||||
|
||||
// Define retry policy for compensation activities
|
||||
WorkflowTaskRetryPolicy compensationRetryPolicy = WorkflowTaskRetryPolicy.newBuilder()
|
||||
.setFirstRetryInterval(Duration.ofSeconds(1))
|
||||
.setMaxNumberOfAttempts(3)
|
||||
.build();
|
||||
|
||||
WorkflowTaskOptions compensationOptions = new WorkflowTaskOptions(compensationRetryPolicy);
|
||||
|
||||
try {
|
||||
// Book flight
|
||||
String flightResult = ctx.callActivity(BookFlightActivity.class.getName(), null, String.class).await();
|
||||
ctx.getLogger().info("Flight booking completed: {}", flightResult);
|
||||
compensations.add("CancelFlight");
|
||||
|
||||
// Book hotel
|
||||
String hotelResult = ctx.callActivity(BookHotelActivity.class.getName(), null, String.class).await();
|
||||
ctx.getLogger().info("Hotel booking completed: {}", hotelResult);
|
||||
compensations.add("CancelHotel");
|
||||
|
||||
// Book car
|
||||
String carResult = ctx.callActivity(BookCarActivity.class.getName(), null, String.class).await();
|
||||
ctx.getLogger().info("Car booking completed: {}", carResult);
|
||||
compensations.add("CancelCar");
|
||||
|
||||
String result = String.format("%s, %s, %s", flightResult, hotelResult, carResult);
|
||||
ctx.getLogger().info("Trip booked successfully: {}", result);
|
||||
ctx.complete(result);
|
||||
|
||||
} catch (TaskFailedException e) {
|
||||
ctx.getLogger().info("******** executing compensation logic ********");
|
||||
ctx.getLogger().error("Activity failed: {}", e.getMessage());
|
||||
|
||||
// Execute compensations in reverse order
|
||||
Collections.reverse(compensations);
|
||||
for (String compensation : compensations) {
|
||||
try {
|
||||
switch (compensation) {
|
||||
case "CancelCar":
|
||||
String carCancelResult = ctx.callActivity(
|
||||
CancelCarActivity.class.getName(),
|
||||
null,
|
||||
compensationOptions,
|
||||
String.class).await();
|
||||
ctx.getLogger().info("Car cancellation completed: {}", carCancelResult);
|
||||
break;
|
||||
|
||||
case "CancelHotel":
|
||||
String hotelCancelResult = ctx.callActivity(
|
||||
CancelHotelActivity.class.getName(),
|
||||
null,
|
||||
compensationOptions,
|
||||
String.class).await();
|
||||
ctx.getLogger().info("Hotel cancellation completed: {}", hotelCancelResult);
|
||||
break;
|
||||
|
||||
case "CancelFlight":
|
||||
String flightCancelResult = ctx.callActivity(
|
||||
CancelFlightActivity.class.getName(),
|
||||
null,
|
||||
compensationOptions,
|
||||
String.class).await();
|
||||
ctx.getLogger().info("Flight cancellation completed: {}", flightCancelResult);
|
||||
break;
|
||||
}
|
||||
} catch (TaskFailedException ex) {
|
||||
// Only catch TaskFailedException for actual activity failures
|
||||
ctx.getLogger().error("Activity failed during compensation: {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
ctx.complete("Workflow failed, compensation applied");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.workflows.WorkflowActivity;
|
||||
import io.dapr.workflows.WorkflowActivityContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CancelCarActivity implements WorkflowActivity {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CancelCarActivity.class);
|
||||
|
||||
@Override
|
||||
public String run(WorkflowActivityContext ctx) {
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
|
||||
// Simulate work
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String result = "Car canceled successfully";
|
||||
logger.info("Activity completed with result: " + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.workflows.WorkflowActivity;
|
||||
import io.dapr.workflows.WorkflowActivityContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CancelFlightActivity implements WorkflowActivity {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CancelFlightActivity.class);
|
||||
|
||||
@Override
|
||||
public String run(WorkflowActivityContext ctx) {
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
|
||||
// Simulate work
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String result = "Flight canceled successfully";
|
||||
logger.info("Activity completed with result: " + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2025 The Dapr Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package io.dapr.examples.workflows.compensation;
|
||||
|
||||
import io.dapr.workflows.WorkflowActivity;
|
||||
import io.dapr.workflows.WorkflowActivityContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CancelHotelActivity implements WorkflowActivity {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CancelHotelActivity.class);
|
||||
|
||||
@Override
|
||||
public String run(WorkflowActivityContext ctx) {
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
|
||||
// Simulate work
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String result = "Hotel canceled successfully";
|
||||
logger.info("Activity completed with result: " + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
5
pom.xml
5
pom.xml
|
|
@ -241,6 +241,11 @@
|
|||
<artifactId>spring-boot-testcontainers</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>testcontainers-dapr</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>toxiproxy</artifactId>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>durabletask-client</artifactId>
|
||||
<version>1.5.4</version>
|
||||
<version>1.5.5</version>
|
||||
</dependency>
|
||||
<!--
|
||||
manually declare durabletask-client's jackson dependencies
|
||||
|
|
|
|||
|
|
@ -55,6 +55,15 @@
|
|||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
Loading…
Reference in New Issue