mirror of https://github.com/dapr/java-sdk.git
Compare commits
95 Commits
v1.14.2-rc
...
master
Author | SHA1 | Date |
---|---|---|
|
e666bbdf2f | |
|
d3674f5aaa | |
|
1e62c73543 | |
|
a822f8b712 | |
|
f73d57eb27 | |
|
6a6957aa42 | |
|
779a4dae28 | |
|
7a4f7d3c02 | |
|
7bb5ffccf1 | |
|
cfb90678a0 | |
|
bbec093254 | |
|
6411797627 | |
|
a159db280e | |
|
8c2c2ee2d4 | |
|
d01da7ae29 | |
|
7cf6533afd | |
|
2454fec841 | |
|
e3fc48d4eb | |
|
981b3b457b | |
|
dcaca773b3 | |
|
e13f934efe | |
|
3a8fd611da | |
|
7e2f81d0e3 | |
|
13a973bf5a | |
|
447e2bfa86 | |
|
114e354363 | |
|
1852cc5590 | |
|
c466d1b743 | |
|
e6f7c6eb06 | |
|
6cecd76745 | |
|
ba3b529830 | |
|
949584f69f | |
|
a99d286a88 | |
|
8ea5ea4f4b | |
|
7291d4c74d | |
|
1e4bcf9b9f | |
|
c3592b446d | |
|
e84d2c4e61 | |
|
e4cc0303fa | |
|
c07e07b782 | |
|
a1ec3ce898 | |
|
910b13ba56 | |
|
824f357f58 | |
|
daf4c8b703 | |
|
551d205b1d | |
|
4e1fbbe2ce | |
|
ab8e41111d | |
|
7ed4d9184c | |
|
ecc94f5b94 | |
|
dcf2d3e359 | |
|
99e21db465 | |
|
c53f000ef2 | |
|
b7e45a06c1 | |
|
80c3a6d122 | |
|
de2dc63389 | |
|
67c5991697 | |
|
8b8684a2db | |
|
9b635dae6d | |
|
ed9a3fb77b | |
|
128cfdeb4b | |
|
ef1fc2242a | |
|
8cb80997cf | |
|
0572e244cb | |
|
02733dcc15 | |
|
505b93acb5 | |
|
bc2b04f24b | |
|
de82451a38 | |
|
f0c35968f4 | |
|
c909d26811 | |
|
58b7f256a3 | |
|
16f9da0c4b | |
|
7990ed79ec | |
|
7b82d7336b | |
|
57f6b96d60 | |
|
c1ee14100b | |
|
ffbb5b39bd | |
|
42b2d88216 | |
|
e2a944eea6 | |
|
5ebc5e359e | |
|
19c662cc2d | |
|
a03f22064e | |
|
bb48276691 | |
|
18a036c193 | |
|
c9b013f0c1 | |
|
641b34a107 | |
|
ff917acf4f | |
|
465c9e0a8d | |
|
ad917d215b | |
|
ed95feeaf4 | |
|
247502a1b1 | |
|
d6c14dee69 | |
|
54f3997bd1 | |
|
7994fe8997 | |
|
5eed6953a1 | |
|
6108547fc2 |
|
@ -38,17 +38,13 @@ if [ "$VARIANT" = "SNAPSHOT" ]; then
|
|||
echo "Invalid snapshot version: $REL_VERSION"
|
||||
exit 3
|
||||
fi
|
||||
branch_name="automation/update_to_next_${current_time}"
|
||||
git checkout -b $branch_name
|
||||
|
||||
# Change is done directly in the master branch.
|
||||
${script_dir}/update_sdk_version.sh $REL_VERSION
|
||||
git clean -xdf
|
||||
git commit -s -m "Update master version to ${REL_VERSION}" -a
|
||||
git push origin $branch_name
|
||||
gh pr create --repo ${GITHUB_REPOSITORY} \
|
||||
--base master \
|
||||
--title "Update master version to ${REL_VERSION}" \
|
||||
--body "Update master version to ${REL_VERSION}"
|
||||
echo "Done."
|
||||
git clean -f -d
|
||||
git push origin master
|
||||
echo "Updated master branch with version ${REL_VERSION}."
|
||||
exit 0
|
||||
elif [ "$VARIANT" = "rc" ]; then
|
||||
echo "Release-candidate version detected: $REL_VERSION"
|
||||
|
@ -107,15 +103,13 @@ fi
|
|||
|
||||
if [ "$VARIANT" = "" ]; then
|
||||
git clean -xdf
|
||||
echo "Creating pull request to update docs ..."
|
||||
branch_name="automation/update_docs_${current_time}"
|
||||
echo "Updating docs in master branch ..."
|
||||
git checkout master
|
||||
git fetch origin
|
||||
git reset --hard origin/master
|
||||
git cherry-pick --strategy=recursive -X theirs $RELEASE_TAG
|
||||
git push origin $branch_name
|
||||
gh pr create --repo ${GITHUB_REPOSITORY} \
|
||||
--base master \
|
||||
--title "Update master docs for ${REL_VERSION} release" \
|
||||
--body "Update master docs for ${REL_VERSION} release"
|
||||
git push origin master
|
||||
echo "Updated docs in master branch."
|
||||
fi
|
||||
|
||||
echo "Done."
|
|
@ -38,13 +38,18 @@ jobs:
|
|||
GOARCH: amd64
|
||||
GOPROXY: https://proxy.golang.org
|
||||
JDK_VER: ${{ matrix.java }}
|
||||
DAPR_CLI_VER: 1.14.0
|
||||
DAPR_RUNTIME_VER: 1.14.4
|
||||
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.14.0/install/install.sh
|
||||
DAPR_CLI_VER: 1.15.0
|
||||
DAPR_RUNTIME_VER: 1.15.7
|
||||
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.15.0/install/install.sh
|
||||
DAPR_CLI_REF:
|
||||
DAPR_REF:
|
||||
TOXIPROXY_URL: https://github.com/Shopify/toxiproxy/releases/download/v2.5.0/toxiproxy-server-linux-amd64
|
||||
steps:
|
||||
- name: Install Stable Docker
|
||||
id: setup_docker
|
||||
uses: docker/setup-docker-action@v4
|
||||
- name: Check Docker version
|
||||
run: docker version
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up OpenJDK ${{ env.JDK_VER }}
|
||||
uses: actions/setup-java@v4
|
||||
|
@ -113,13 +118,17 @@ jobs:
|
|||
run: ./mvnw compile -B -q
|
||||
- name: Unit tests
|
||||
run: ./mvnw test # making it temporarily verbose.
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Codecov
|
||||
uses: codecov/codecov-action@v4.1.0
|
||||
uses: codecov/codecov-action@v5.4.3
|
||||
- name: Install jars
|
||||
run: ./mvnw install -q -B -DskipTests
|
||||
- name: Integration tests using spring boot version ${{ matrix.spring-boot-version }}
|
||||
id: integration_tests
|
||||
run: PRODUCT_SPRING_BOOT_VERSION=${{ matrix.spring-boot-version }} ./mvnw -B -Pintegration-tests verify
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Upload test report for sdk
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
@ -174,15 +183,12 @@ jobs:
|
|||
echo "DEPLOY_OSSRH=true" >> $GITHUB_ENV
|
||||
- name: Install jars
|
||||
if: env.DEPLOY_OSSRH == 'true'
|
||||
run: ./mvnw install -B -q
|
||||
- name: Publish to Central Publisher Portal
|
||||
run: ./mvnw install -DskipTests -B -q
|
||||
- name: Publish to ossrh
|
||||
if: env.DEPLOY_OSSRH == 'true'
|
||||
run: |
|
||||
echo ${{ secrets.GPG_PRIVATE_KEY }} | base64 -d > private-key.gpg
|
||||
export GPG_TTY=$(tty)
|
||||
gpg --batch --import private-key.gpg
|
||||
echo "Starting Maven deploy..."
|
||||
./mvnw -V -B -Dgpg.skip=false -s settings.xml deploy
|
||||
echo "Maven deploy completed"
|
||||
curl -X POST https://central.sonatype.com/manual/upload/defaultRepository/io.dapr
|
||||
echo "Manual upload completed"
|
||||
curl -X POST https://ossrh-staging-api.central.sonatype.com/manual/upload/defaultRepository/io.dapr
|
||||
|
|
|
@ -35,12 +35,12 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Run FOSSA Scan"
|
||||
uses: fossas/fossa-action@v1.3.3 # Use a specific version if locking is preferred
|
||||
uses: fossas/fossa-action@v1.7.0 # Use a specific version if locking is preferred
|
||||
with:
|
||||
api-key: ${{ env.FOSSA_API_KEY }}
|
||||
|
||||
- name: "Run FOSSA Test"
|
||||
uses: fossas/fossa-action@v1.3.3 # Use a specific version if locking is preferred
|
||||
uses: fossas/fossa-action@v1.7.0 # Use a specific version if locking is preferred
|
||||
with:
|
||||
api-key: ${{ env.FOSSA_API_KEY }}
|
||||
run-tests: true
|
||||
|
|
|
@ -37,9 +37,9 @@ jobs:
|
|||
GOARCH: amd64
|
||||
GOPROXY: https://proxy.golang.org
|
||||
JDK_VER: ${{ matrix.java }}
|
||||
DAPR_CLI_VER: 1.14.0
|
||||
DAPR_RUNTIME_VER: 1.14.4
|
||||
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.14.0/install/install.sh
|
||||
DAPR_CLI_VER: 1.15.0
|
||||
DAPR_RUNTIME_VER: 1.15.7
|
||||
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.15.0/install/install.sh
|
||||
DAPR_CLI_REF:
|
||||
DAPR_REF:
|
||||
steps:
|
||||
|
@ -49,6 +49,11 @@ jobs:
|
|||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ env.JDK_VER }}
|
||||
- name: Install Stable Docker
|
||||
id: setup_docker
|
||||
uses: docker/setup-docker-action@v4
|
||||
- name: Check Docker version
|
||||
run: docker version
|
||||
- name: Set up Dapr CLI
|
||||
run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }}
|
||||
- name: Set up Go ${{ env.GOVER }}
|
||||
|
@ -108,63 +113,113 @@ jobs:
|
|||
run: ./mvnw compile -q
|
||||
- name: Install jars
|
||||
run: ./mvnw install -q
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate Jobs example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/jobs/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate conversation ai example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/conversation/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate invoke http example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/invoke/http/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate invoke grpc example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/invoke/grpc/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate tracing example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/tracing/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate expection handling example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/exception/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate state example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/state/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate pubsub example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/pubsub/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate bindings HTTP example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/bindings/http/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate secrets example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/secrets/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate unit testing example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/unittesting/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate Configuration API example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/configuration/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate actors example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/actors/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate query state HTTP example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/querystate/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate workflows example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/workflows/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate streaming subscription example
|
||||
working-directory: ./examples
|
||||
run: |
|
||||
mm.py ./src/main/java/io/dapr/examples/pubsub/stream/README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate Spring Boot examples
|
||||
working-directory: ./spring-boot-examples
|
||||
run: |
|
||||
mm.py README.md
|
||||
mm.py README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
- name: Validate Spring Boot Workflow examples
|
||||
working-directory: ./spring-boot-examples/workflows
|
||||
run: |
|
||||
mm.py README.md
|
||||
env:
|
||||
DOCKER_HOST: ${{steps.setup_docker.outputs.sock}}
|
||||
|
|
|
@ -12,6 +12,8 @@ This project has adopted the [Contributor Covenant Code of Conduct](https://gith
|
|||
|
||||
Contributions come in many forms: submitting issues, writing code, participating in discussions and community calls.
|
||||
|
||||
To learn more about becoming a contributor and the different roles within the Dapr community (Contributor, Approver, Maintainer), please refer to our [Community Membership](https://github.com/dapr/community/blob/master/community-membership.md) documentation.
|
||||
|
||||
This document provides the guidelines for how to contribute to the Dapr project.
|
||||
|
||||
## Issues
|
||||
|
@ -49,18 +51,77 @@ Before you file an issue, make sure you've checked the following:
|
|||
|
||||
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 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
|
||||
|
||||
All contributions come through pull requests. To submit a proposed change, we recommend following this workflow:
|
||||
|
||||
1. Make sure there's an issue (bug or proposal) raised, which sets the expectations for the contribution you are about to make.
|
||||
1. Fork the relevant repo and create a new branch
|
||||
1. Create your change
|
||||
2. Fork the relevant repo and create a new branch
|
||||
3. Create your change
|
||||
- Code changes require tests
|
||||
1. Update relevant documentation for the change
|
||||
1. Commit and open a PR
|
||||
1. Wait for the CI process to finish and make sure all checks are green
|
||||
1. A maintainer of the project will be assigned, and you can expect a review within a few days
|
||||
4. Update relevant documentation for the change
|
||||
5. Check the code style
|
||||
6. Commit and open a PR
|
||||
7. Wait for the CI process to finish and make sure all checks are green
|
||||
8. A maintainer of the project will be assigned, and you can expect a review within a few days
|
||||
9. All the files have the Copyright header.
|
||||
|
||||
### Configure the code style with checkstyle
|
||||
|
||||
The project contains a checkstyle file (`checkstyle.xml`) that must be used for formatting the code.
|
||||
|
||||
* IntelliJ IDEA
|
||||
You can use [CheckStyle-IDEA plugin](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea).
|
||||
* VSCode
|
||||
You can use [Checkstyle for Java](https://marketplace.visualstudio.com/items?itemName=shengchen.vscode-checkstyle).
|
||||
* Eclipse
|
||||
You can use [Eclipse Checkstyle Plugin](https://checkstyle.org/eclipse-cs/#!/)
|
||||
|
||||
#### Use work-in-progress PRs for early feedback
|
||||
|
||||
|
@ -120,6 +181,10 @@ A non-exclusive list of code that must be places in `vendor/`:
|
|||
|
||||
**Thank You!** - Your contributions to open source, large or small, make projects like this possible. Thank you for taking the time to contribute.
|
||||
|
||||
## Github Dapr Bot Commands
|
||||
|
||||
Checkout the [daprbot documentation](https://docs.dapr.io/contributing/daprbot/) for Github commands you can run in this repo for common tasks. For example, you can run the `/assign` (as a comment on an issue) to assign the issue to yourself.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Contributor Covenant Code of Conduct](https://github.com/dapr/community/blob/master/CODE-OF-CONDUCT.md)
|
||||
|
|
|
@ -112,6 +112,7 @@
|
|||
<module name="ModifierOrder"/>
|
||||
<module name="EmptyLineSeparator">
|
||||
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||
<property name="allowMultipleEmptyLines" value="false"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapDot"/>
|
||||
|
@ -287,4 +288,13 @@
|
|||
<module name="SuppressWarningsHolder"/>
|
||||
</module>
|
||||
<module name="SuppressWarningsFilter"/>
|
||||
<module name="RegexpHeader">
|
||||
<property name="headerFile" value="${checkstyle.header.file}"/>
|
||||
<property name="fileExtensions" value="java,xml"/>
|
||||
</module>
|
||||
<module name="SuppressionSingleFilter">
|
||||
<property name="checks" value="RegexpHeader"/>
|
||||
<property name="files" value=".*\.properties$"/>
|
||||
</module>
|
||||
<module name="NewlineAtEndOfFile"/>
|
||||
</module>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-parent</artifactId>
|
||||
<version>0.14.2-rc-4</version>
|
||||
<version>0.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-spring-boot-autoconfigure</artifactId>
|
||||
|
@ -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>
|
||||
|
|
|
@ -13,31 +13,37 @@ limitations under the License.
|
|||
|
||||
package io.dapr.spring.boot.autoconfigure.client;
|
||||
|
||||
class PropertiesDaprConnectionDetails implements DaprConnectionDetails {
|
||||
public class ClientPropertiesDaprConnectionDetails implements DaprConnectionDetails {
|
||||
|
||||
private final DaprClientProperties daprClientProperties;
|
||||
|
||||
public PropertiesDaprConnectionDetails(DaprClientProperties daprClientProperties) {
|
||||
public ClientPropertiesDaprConnectionDetails(DaprClientProperties daprClientProperties) {
|
||||
this.daprClientProperties = daprClientProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String httpEndpoint() {
|
||||
public String getHttpEndpoint() {
|
||||
return this.daprClientProperties.getHttpEndpoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String grpcEndpoint() {
|
||||
public String getGrpcEndpoint() {
|
||||
return this.daprClientProperties.getGrpcEndpoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer httpPort() {
|
||||
public Integer getHttpPort() {
|
||||
return this.daprClientProperties.getHttpPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer grpcPort() {
|
||||
public Integer getGrpcPort() {
|
||||
return this.daprClientProperties.getGrpcPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApiToken() {
|
||||
return this.daprClientProperties.getApiToken();
|
||||
}
|
||||
|
||||
}
|
|
@ -37,25 +37,42 @@ public class DaprClientAutoConfiguration {
|
|||
@Bean
|
||||
@ConditionalOnMissingBean(DaprConnectionDetails.class)
|
||||
DaprConnectionDetails daprConnectionDetails(DaprClientProperties properties) {
|
||||
return new PropertiesDaprConnectionDetails(properties);
|
||||
return new ClientPropertiesDaprConnectionDetails(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DaprClientBuilder daprClientBuilder(DaprConnectionDetails daprConnectionDetails) {
|
||||
DaprClientBuilder builder = new DaprClientBuilder();
|
||||
if (daprConnectionDetails.httpEndpoint() != null) {
|
||||
builder.withPropertyOverride(Properties.HTTP_ENDPOINT, daprConnectionDetails.httpEndpoint());
|
||||
DaprClientBuilder builder = createDaprClientBuilder();
|
||||
String httpEndpoint = daprConnectionDetails.getHttpEndpoint();
|
||||
|
||||
if (httpEndpoint != null) {
|
||||
builder.withPropertyOverride(Properties.HTTP_ENDPOINT, httpEndpoint);
|
||||
}
|
||||
if (daprConnectionDetails.grpcEndpoint() != null) {
|
||||
builder.withPropertyOverride(Properties.GRPC_ENDPOINT, daprConnectionDetails.grpcEndpoint());
|
||||
|
||||
String grpcEndpoint = daprConnectionDetails.getGrpcEndpoint();
|
||||
|
||||
if (grpcEndpoint != null) {
|
||||
builder.withPropertyOverride(Properties.GRPC_ENDPOINT, grpcEndpoint);
|
||||
}
|
||||
if (daprConnectionDetails.httpPort() != null) {
|
||||
builder.withPropertyOverride(Properties.HTTP_PORT, String.valueOf(daprConnectionDetails.httpPort()));
|
||||
|
||||
Integer httpPort = daprConnectionDetails.getHttpPort();
|
||||
|
||||
if (httpPort != null) {
|
||||
builder.withPropertyOverride(Properties.HTTP_PORT, String.valueOf(httpPort));
|
||||
}
|
||||
if (daprConnectionDetails.grpcPort() != null) {
|
||||
builder.withPropertyOverride(Properties.GRPC_PORT, String.valueOf(daprConnectionDetails.grpcPort()));
|
||||
|
||||
Integer grpcPort = daprConnectionDetails.getGrpcPort();
|
||||
|
||||
if (grpcPort != null) {
|
||||
builder.withPropertyOverride(Properties.GRPC_PORT, String.valueOf(grpcPort));
|
||||
}
|
||||
|
||||
String apiToken = daprConnectionDetails.getApiToken();
|
||||
if (apiToken != null) {
|
||||
builder.withPropertyOverride(Properties.API_TOKEN, apiToken);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
@ -90,18 +107,55 @@ public class DaprClientAutoConfiguration {
|
|||
@ConditionalOnMissingBean
|
||||
WorkflowRuntimeBuilder daprWorkflowRuntimeBuilder(DaprConnectionDetails daprConnectionDetails) {
|
||||
Properties properties = createPropertiesFromConnectionDetails(daprConnectionDetails);
|
||||
|
||||
return new WorkflowRuntimeBuilder(properties);
|
||||
}
|
||||
|
||||
private Properties createPropertiesFromConnectionDetails(DaprConnectionDetails daprConnectionDetails) {
|
||||
final Map<String, String> propertyOverrides = new HashMap<>();
|
||||
propertyOverrides.put(Properties.HTTP_ENDPOINT.getName(), daprConnectionDetails.httpEndpoint());
|
||||
propertyOverrides.put(Properties.HTTP_PORT.getName(), String.valueOf(daprConnectionDetails.httpPort()));
|
||||
propertyOverrides.put(Properties.GRPC_ENDPOINT.getName(), daprConnectionDetails.grpcEndpoint());
|
||||
propertyOverrides.put(Properties.GRPC_PORT.getName(), String.valueOf(daprConnectionDetails.grpcPort()));
|
||||
/**
|
||||
* We use this method in tests to override the default DaprClientBuilder.
|
||||
*/
|
||||
protected DaprClientBuilder createDaprClientBuilder() {
|
||||
return new DaprClientBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Properties object from the DaprConnectionDetails.
|
||||
*
|
||||
* @param daprConnectionDetails the DaprConnectionDetails
|
||||
* @return the Properties object
|
||||
*/
|
||||
protected Properties createPropertiesFromConnectionDetails(DaprConnectionDetails daprConnectionDetails) {
|
||||
Map<String, String> propertyOverrides = new HashMap<>();
|
||||
String httpEndpoint = daprConnectionDetails.getHttpEndpoint();
|
||||
|
||||
if (httpEndpoint != null) {
|
||||
propertyOverrides.put(Properties.HTTP_ENDPOINT.getName(), httpEndpoint);
|
||||
}
|
||||
|
||||
Integer httpPort = daprConnectionDetails.getHttpPort();
|
||||
|
||||
if (httpPort != null) {
|
||||
propertyOverrides.put(Properties.HTTP_PORT.getName(), String.valueOf(httpPort));
|
||||
}
|
||||
|
||||
String grpcEndpoint = daprConnectionDetails.getGrpcEndpoint();
|
||||
|
||||
if (grpcEndpoint != null) {
|
||||
propertyOverrides.put(Properties.GRPC_ENDPOINT.getName(), grpcEndpoint);
|
||||
}
|
||||
|
||||
Integer grpcPort = daprConnectionDetails.getGrpcPort();
|
||||
|
||||
if (grpcPort != null) {
|
||||
propertyOverrides.put(Properties.GRPC_PORT.getName(), String.valueOf(grpcPort));
|
||||
}
|
||||
|
||||
String apiToken = daprConnectionDetails.getApiToken();
|
||||
if (apiToken != null) {
|
||||
propertyOverrides.put(Properties.API_TOKEN.getName(), apiToken);
|
||||
}
|
||||
|
||||
return new Properties(propertyOverrides);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ limitations under the License.
|
|||
|
||||
package io.dapr.spring.boot.autoconfigure.client;
|
||||
|
||||
import io.dapr.spring.data.DaprKeyValueAdapterResolver;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "dapr.client")
|
||||
|
@ -22,7 +21,7 @@ public class DaprClientProperties {
|
|||
private String grpcEndpoint;
|
||||
private Integer httpPort;
|
||||
private Integer grpcPort;
|
||||
|
||||
private String apiToken;
|
||||
|
||||
/**
|
||||
* Constructs a {@link DaprClientProperties}.
|
||||
|
@ -36,12 +35,15 @@ public class DaprClientProperties {
|
|||
* @param grpcEndpoint grpc endpoint to interact with the Dapr Sidecar
|
||||
* @param httpPort http port to interact with the Dapr Sidecar
|
||||
* @param grpcPort grpc port to interact with the Dapr Sidecar
|
||||
* @param apiToken dapr API token to interact with the Dapr Sidecar
|
||||
*/
|
||||
public DaprClientProperties(String httpEndpoint, String grpcEndpoint, Integer httpPort, Integer grpcPort) {
|
||||
public DaprClientProperties(String httpEndpoint, String grpcEndpoint, Integer httpPort, Integer grpcPort,
|
||||
String apiToken) {
|
||||
this.httpEndpoint = httpEndpoint;
|
||||
this.grpcEndpoint = grpcEndpoint;
|
||||
this.httpPort = httpPort;
|
||||
this.grpcPort = grpcPort;
|
||||
this.apiToken = apiToken;
|
||||
}
|
||||
|
||||
public String getHttpEndpoint() {
|
||||
|
@ -75,4 +77,12 @@ public class DaprClientProperties {
|
|||
public void setGrpcPort(Integer grpcPort) {
|
||||
this.grpcPort = grpcPort;
|
||||
}
|
||||
|
||||
public String getApiToken() {
|
||||
return apiToken;
|
||||
}
|
||||
|
||||
public void setApiToken(String apiToken) {
|
||||
this.apiToken = apiToken;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,15 @@ package io.dapr.spring.boot.autoconfigure.client;
|
|||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
|
||||
public interface DaprConnectionDetails extends ConnectionDetails {
|
||||
String httpEndpoint();
|
||||
|
||||
String grpcEndpoint();
|
||||
String getHttpEndpoint();
|
||||
|
||||
Integer httpPort();
|
||||
String getGrpcEndpoint();
|
||||
|
||||
Integer getHttpPort();
|
||||
|
||||
Integer getGrpcPort();
|
||||
|
||||
String getApiToken();
|
||||
|
||||
Integer grpcPort();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ package io.dapr.spring.boot.autoconfigure.pubsub;
|
|||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
|
||||
@ConfigurationProperties(prefix = DaprPubSubProperties.CONFIG_PREFIX)
|
||||
public class DaprPubSubProperties {
|
||||
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright 2024 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.spring.boot.autoconfigure.client;
|
||||
|
||||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.config.Properties;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DaprClientAutoConfiguration}.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DaprClientAutoConfigurationTest {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DaprClientAutoConfiguration.class));
|
||||
|
||||
@Mock
|
||||
private DaprConnectionDetails connectionDetails;
|
||||
|
||||
@Mock
|
||||
private DaprClientBuilder builder;
|
||||
|
||||
private DaprClientAutoConfiguration configuration;
|
||||
|
||||
@Test
|
||||
void daprClientBuilder() {
|
||||
contextRunner.run(context -> assertThat(context).hasSingleBean(DaprClientBuilder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void daprClient() {
|
||||
contextRunner.run(context -> assertThat(context).hasSingleBean(DaprClient.class));
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configuration = new TestDaprClientAutoConfiguration(builder);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should override HTTP endpoint if it exists")
|
||||
void shouldOverrideHttpEndpointIfExists() {
|
||||
String httpEndpoint = "http://localhost:3500";
|
||||
|
||||
when(connectionDetails.getHttpEndpoint()).thenReturn(httpEndpoint);
|
||||
|
||||
configuration.daprClientBuilder(connectionDetails);
|
||||
|
||||
verify(builder).withPropertyOverride(Properties.HTTP_ENDPOINT, httpEndpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should override GRPC endpoint if it exists")
|
||||
void shouldOverrideGrpcEndpointIfExists() {
|
||||
String grpcEndpoint = "grpc://localhost:5001";
|
||||
|
||||
when(connectionDetails.getGrpcEndpoint()).thenReturn(grpcEndpoint);
|
||||
|
||||
configuration.daprClientBuilder(connectionDetails);
|
||||
|
||||
verify(builder).withPropertyOverride(Properties.GRPC_ENDPOINT, grpcEndpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should override HTTP port if it exists")
|
||||
void shouldOverrideHttpPortIfExists() {
|
||||
Integer httpPort = 3600;
|
||||
|
||||
when(connectionDetails.getHttpPort()).thenReturn(httpPort);
|
||||
|
||||
configuration.daprClientBuilder(connectionDetails);
|
||||
|
||||
verify(builder).withPropertyOverride(Properties.HTTP_PORT, String.valueOf(httpPort));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should override GRPC port if it exists")
|
||||
void shouldOverrideGrpcPortIfExists() {
|
||||
Integer grpcPort = 6001;
|
||||
|
||||
when(connectionDetails.getGrpcPort()).thenReturn(grpcPort);
|
||||
|
||||
configuration.daprClientBuilder(connectionDetails);
|
||||
|
||||
verify(builder).withPropertyOverride(Properties.GRPC_PORT, String.valueOf(grpcPort));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should override HTTP endpoint in properties if it exists")
|
||||
void shouldOverrideHttpEndpointInPropertiesIfExists() {
|
||||
String httpEndpoint = "http://localhost:3500";
|
||||
|
||||
when(connectionDetails.getHttpEndpoint()).thenReturn(httpEndpoint);
|
||||
|
||||
Properties reuslt = configuration.createPropertiesFromConnectionDetails(connectionDetails);
|
||||
|
||||
assertThat(reuslt.getValue(Properties.HTTP_ENDPOINT)).isEqualTo(httpEndpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should override GRPC endpoint in properties if it exists")
|
||||
void shouldOverrideGrpcEndpointPropertiesIfExists() {
|
||||
String grpcEndpoint = "grpc://localhost:3500";
|
||||
|
||||
when(connectionDetails.getGrpcEndpoint()).thenReturn(grpcEndpoint);
|
||||
|
||||
Properties result = configuration.createPropertiesFromConnectionDetails(connectionDetails);
|
||||
|
||||
assertThat(result.getValue(Properties.GRPC_ENDPOINT)).isEqualTo(grpcEndpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should override HTTP port in properties if it exists")
|
||||
void shouldOverrideHttpPortPropertiesIfExists() {
|
||||
Integer httpPort = 3600;
|
||||
|
||||
when(connectionDetails.getHttpPort()).thenReturn(httpPort);
|
||||
|
||||
Properties result = configuration.createPropertiesFromConnectionDetails(connectionDetails);
|
||||
|
||||
assertThat(result.getValue(Properties.HTTP_PORT)).isEqualTo(httpPort);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should override GRPC port in properties if it exists")
|
||||
void shouldOverrideGrpcPortPropertiesIfExists() {
|
||||
Integer grpcPort = 6001;
|
||||
|
||||
when(connectionDetails.getGrpcPort()).thenReturn(grpcPort);
|
||||
|
||||
Properties result = configuration.createPropertiesFromConnectionDetails(connectionDetails);
|
||||
|
||||
assertThat(result.getValue(Properties.GRPC_PORT)).isEqualTo(grpcPort);
|
||||
}
|
||||
|
||||
private static class TestDaprClientAutoConfiguration extends DaprClientAutoConfiguration {
|
||||
|
||||
private final DaprClientBuilder daprClientBuilder;
|
||||
|
||||
public TestDaprClientAutoConfiguration(DaprClientBuilder daprClientBuilder) {
|
||||
this.daprClientBuilder = daprClientBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DaprClientBuilder createDaprClientBuilder() {
|
||||
return daprClientBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 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.spring.boot.autoconfigure.client;
|
||||
|
||||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DaprClientAutoConfiguration}.
|
||||
*/
|
||||
class DaprClientAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DaprClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void daprClientBuilder() {
|
||||
contextRunner.run(context -> assertThat(context).hasSingleBean(DaprClientBuilder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void daprClient() {
|
||||
contextRunner.run(context -> assertThat(context).hasSingleBean(DaprClient.class));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.spring.boot.autoconfigure.client;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
public class DaprClientPropertiesTest {
|
||||
|
||||
|
||||
private final ApplicationContextRunner runner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(EnableDaprClientProperties.class);
|
||||
|
||||
@Test
|
||||
@DisplayName("Should create DaprClientProperties correctly through constructor")
|
||||
public void shouldCreateDaprClientPropertiesCorrectly() {
|
||||
|
||||
DaprClientProperties properties = new DaprClientProperties(
|
||||
"http://localhost", "localhost", 3500, 50001, "ABC"
|
||||
);
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
softly.assertThat(properties.getGrpcEndpoint()).isEqualTo("localhost");
|
||||
softly.assertThat(properties.getHttpEndpoint()).isEqualTo("http://localhost");
|
||||
softly.assertThat(properties.getHttpPort()).isEqualTo(3500);
|
||||
softly.assertThat(properties.getGrpcPort()).isEqualTo(50001);
|
||||
softly.assertThat(properties.getApiToken()).isEqualTo("ABC");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should create DaprClientProperties correctly through setters")
|
||||
public void shouldSetDaprClientPropertiesCorrectly() {
|
||||
|
||||
DaprClientProperties properties = new DaprClientProperties();
|
||||
|
||||
properties.setGrpcEndpoint("localhost");
|
||||
properties.setGrpcPort(50001);
|
||||
properties.setHttpEndpoint("http://localhost");
|
||||
properties.setHttpPort(3500);
|
||||
properties.setApiToken("ABC");
|
||||
|
||||
SoftAssertions.assertSoftly(softAssertions -> {
|
||||
softAssertions.assertThat(properties.getGrpcEndpoint()).isEqualTo("localhost");
|
||||
softAssertions.assertThat(properties.getHttpEndpoint()).isEqualTo("http://localhost");
|
||||
softAssertions.assertThat(properties.getHttpPort()).isEqualTo(3500);
|
||||
softAssertions.assertThat(properties.getGrpcPort()).isEqualTo(50001);
|
||||
softAssertions.assertThat(properties.getApiToken()).isEqualTo("ABC");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should map DaprClient properties correctly")
|
||||
public void shouldMapDaprClientProperties() {
|
||||
|
||||
runner.withSystemProperties(
|
||||
"dapr.client.http-endpoint=http://localhost",
|
||||
"dapr.client.http-port=3500",
|
||||
"dapr.client.grpc-endpoint=localhost",
|
||||
"dapr.client.grpc-port=50001"
|
||||
).run(context -> {
|
||||
DaprClientProperties properties = context.getBean(DaprClientProperties.class);
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
softly.assertThat(properties.getGrpcEndpoint()).isEqualTo("localhost");
|
||||
softly.assertThat(properties.getHttpEndpoint()).isEqualTo("http://localhost");
|
||||
softly.assertThat(properties.getHttpPort()).isEqualTo(3500);
|
||||
softly.assertThat(properties.getGrpcPort()).isEqualTo(50001);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@EnableConfigurationProperties(DaprClientProperties.class)
|
||||
static class EnableDaprClientProperties {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.spring.boot.autoconfigure.pubsub;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
public class DaprPubSubPropertiesTest {
|
||||
|
||||
final ApplicationContextRunner runner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(EnableDaprPubSubProperties.class);
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("Should configure properties with setters")
|
||||
void shouldSetProperties() {
|
||||
DaprPubSubProperties properties = new DaprPubSubProperties();
|
||||
properties.setName("pubsub");
|
||||
properties.setObservationEnabled(false);
|
||||
|
||||
SoftAssertions.assertSoftly(softAssertions -> {
|
||||
softAssertions.assertThat(properties.getName()).isEqualTo("pubsub");
|
||||
softAssertions.assertThat(properties.isObservationEnabled()).isEqualTo(false);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should map DaprPubSubProperties correctly")
|
||||
void shouldMapDaprPubSubPropertiesCorrectly() {
|
||||
runner.withPropertyValues(
|
||||
"dapr.pubsub.name=pubsub",
|
||||
"dapr.pubsub.observation-enabled=true"
|
||||
).run(context -> {
|
||||
DaprPubSubProperties properties = context.getBean(DaprPubSubProperties.class);
|
||||
|
||||
SoftAssertions.assertSoftly(softAssertions -> {
|
||||
softAssertions.assertThat(properties.getName()).isEqualTo("pubsub");
|
||||
softAssertions.assertThat(properties.isObservationEnabled()).isEqualTo(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@EnableConfigurationProperties(DaprPubSubProperties.class)
|
||||
static class EnableDaprPubSubProperties {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2021 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.spring.boot.autoconfigure.statestore;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
public class DaprStateStorePropertiesTest {
|
||||
|
||||
|
||||
final ApplicationContextRunner runner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(EnableDaprStateStoreProperties.class);
|
||||
|
||||
@Test
|
||||
@DisplayName("Should create DaprStateStoreProperties via constructor")
|
||||
void shouldSetDaprStateStorePropertiesCorrectly() {
|
||||
DaprStateStoreProperties properties = new DaprStateStoreProperties();
|
||||
properties.setBinding("binding");
|
||||
properties.setName("name");
|
||||
|
||||
SoftAssertions.assertSoftly(softAssertions -> {
|
||||
softAssertions.assertThat(properties.getName()).isEqualTo("name");
|
||||
softAssertions.assertThat(properties.getBinding()).isEqualTo("binding");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should map Dapr state store properties correctly")
|
||||
void shouldMapDaprStateStoreProperties() {
|
||||
runner.withPropertyValues(
|
||||
"dapr.statestore.name=name",
|
||||
"dapr.statestore.binding=binding"
|
||||
).run(context -> {
|
||||
DaprStateStoreProperties properties = context.getBean(DaprStateStoreProperties.class);
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
softly.assertThat(properties.getBinding()).isEqualTo("binding");
|
||||
softly.assertThat(properties.getName()).isEqualTo("name");
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@EnableConfigurationProperties(DaprStateStoreProperties.class)
|
||||
static class EnableDaprStateStoreProperties {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-parent</artifactId>
|
||||
<version>0.14.2-rc-4</version>
|
||||
<version>0.16.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -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>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-parent</artifactId>
|
||||
<version>0.14.2-rc-4</version>
|
||||
<version>0.16.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-parent</artifactId>
|
||||
<version>0.14.2-rc-4</version>
|
||||
<version>0.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-spring-boot-tests</artifactId>
|
||||
|
@ -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>
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
/*
|
||||
* Copyright 2021 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.spring.boot.testcontainers.service.connection;
|
||||
|
||||
import io.dapr.spring.boot.autoconfigure.client.DaprConnectionDetails;
|
||||
|
@ -23,23 +36,31 @@ public class DaprContainerConnectionDetailsFactory
|
|||
}
|
||||
|
||||
@Override
|
||||
public String httpEndpoint() {
|
||||
public String getHttpEndpoint() {
|
||||
return getContainer().getHttpEndpoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String grpcEndpoint() {
|
||||
public String getGrpcEndpoint() {
|
||||
return getContainer().getGrpcEndpoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer httpPort() {
|
||||
public Integer getHttpPort() {
|
||||
return getContainer().getHttpPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer grpcPort() {
|
||||
public Integer getGrpcPort() {
|
||||
return getContainer().getGrpcPort();
|
||||
}
|
||||
|
||||
/*
|
||||
* No API Token for local container
|
||||
*/
|
||||
@Override
|
||||
public String getApiToken() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-parent</artifactId>
|
||||
<version>0.14.2-rc-4</version>
|
||||
<version>0.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-spring-data</artifactId>
|
||||
|
@ -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>
|
||||
|
|
|
@ -76,7 +76,6 @@ public class MySQLDaprKeyValueAdapter extends AbstractDaprKeyValueAdapter {
|
|||
this.bindingName = bindingName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> getAllOf(String keyspace, Class<T> type) {
|
||||
Assert.hasText(keyspace, "Keyspace must not be empty");
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
/*
|
||||
* Copyright 2021 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.spring.data.repository.query;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
|
@ -18,7 +31,6 @@ public class DaprPredicate implements Predicate<Object> {
|
|||
this(path, expected, (valueToCompare) -> ObjectUtils.nullSafeEquals(valueToCompare, expected));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link DaprPredicate}.
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-parent</artifactId>
|
||||
<version>0.14.2-rc-4</version>
|
||||
<version>0.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-spring-messaging</artifactId>
|
||||
|
@ -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>
|
||||
|
|
|
@ -192,7 +192,6 @@ public class DaprMessagingTemplate<T> implements DaprMessagingOperations<T>, App
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void send() {
|
||||
template.doSend(topic, message);
|
||||
|
@ -202,7 +201,5 @@ public class DaprMessagingTemplate<T> implements DaprMessagingOperations<T>, App
|
|||
public Mono<Void> sendAsync() {
|
||||
return template.doSendAsync(topic, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ public final class DaprMessagingSenderContext extends SenderContext<DaprMessagin
|
|||
return carrier.properties();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The name of the bean sending the message (typically a {@code DaprMessagingTemplate}).
|
||||
* @return the name of the bean sending the message
|
||||
|
@ -75,7 +74,6 @@ public final class DaprMessagingSenderContext extends SenderContext<DaprMessagin
|
|||
return this.destination;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Acts as a carrier for a Dapr message and records the propagated properties for
|
||||
* later access by the Dapr.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-parent</artifactId>
|
||||
<version>0.14.2-rc-4</version>
|
||||
<version>0.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-spring-workflows</artifactId>
|
||||
|
@ -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>
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
/*
|
||||
* Copyright 2021 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.spring.workflows.config;
|
||||
|
||||
import io.dapr.workflows.Workflow;
|
||||
|
@ -46,10 +59,9 @@ public class DaprWorkflowsConfiguration implements ApplicationContextAware {
|
|||
workflowRuntimeBuilder.registerActivity(activity);
|
||||
}
|
||||
|
||||
try (WorkflowRuntime runtime = workflowRuntimeBuilder.build()) {
|
||||
LOGGER.info("Starting workflow runtime ... ");
|
||||
runtime.start(false);
|
||||
}
|
||||
WorkflowRuntime runtime = workflowRuntimeBuilder.build();
|
||||
LOGGER.info("Starting workflow runtime ... ");
|
||||
runtime.start(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
package io.dapr.spring.workflows.config;
|
||||
/*
|
||||
* Copyright 2021 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.spring.workflows.config;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
<parent>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-parent</artifactId>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.14.2-rc-4</version>
|
||||
<version>0.16.0-SNAPSHOT</version>
|
||||
<name>dapr-spring-parent</name>
|
||||
<description>SDK extension for Spring and Spring Boot</description>
|
||||
|
||||
|
@ -28,10 +28,12 @@
|
|||
</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.11.2</junit.version>
|
||||
<dapr.spring.version>0.16.0-SNAPSHOT</dapr.spring.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -41,55 +43,125 @@
|
|||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<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>
|
||||
<version>${springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</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>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Dapr dependencies -->
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-actors</artifactId>
|
||||
<version>${dapr.sdk.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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.gmazzo.okhttp.mock</groupId>
|
||||
<artifactId>mock-client</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -12,12 +12,16 @@ When contributing to the [Java SDK](https://github.com/dapr/java-sdk) the follow
|
|||
|
||||
The `examples` directory contains code samples for users to run to try out specific functionality of the various Java SDK packages and extensions. When writing new and updated samples keep in mind:
|
||||
|
||||
- All examples should be runnable on Windows, Linux, and MacOS. While Java code is consistent among operating systems, any pre/post example commands should provide options through [codetabs]({{< ref "contributing-docs.md#tabbed-content" >}})
|
||||
- All examples should be runnable on Windows, Linux, and MacOS. While Java code is consistent among operating systems, any pre/post example commands should provide options through [tabpane]({{% ref "contributing-docs.md#tabbed-content" %}})
|
||||
- Contain steps to download/install any required pre-requisites. Someone coming in with a fresh OS install should be able to start on the example and complete it without an error. Links to external download pages are fine.
|
||||
|
||||
## Docs
|
||||
|
||||
The `daprdocs` directory contains the markdown files that are rendered into the [Dapr Docs](https://docs.dapr.io) website. When the documentation website is built, this repo is cloned and configured so that its contents are rendered with the docs content. When writing docs, keep in mind:
|
||||
|
||||
- All rules in the [docs guide]({{< ref contributing-docs.md >}}) should be followed in addition to these.
|
||||
- All rules in the [docs guide]({{% ref contributing-docs.md %}}) should be followed in addition to these.
|
||||
- All files and directories should be prefixed with `java-` to ensure all file/directory names are globally unique across all Dapr documentation.
|
||||
|
||||
## Github Dapr Bot Commands
|
||||
|
||||
Checkout the [daprbot documentation](https://docs.dapr.io/contributing/daprbot/) for Github commands you can run in this repo for common tasks. For example, you can run the `/assign` (as a comment on an issue) to assign the issue to yourself.
|
||||
|
|
|
@ -15,8 +15,8 @@ Dapr offers a variety of packages to help with the development of Java applicati
|
|||
|
||||
## Prerequisites
|
||||
|
||||
- [Dapr CLI]({{< ref install-dapr-cli.md >}}) installed
|
||||
- Initialized [Dapr environment]({{< ref install-dapr-selfhost.md >}})
|
||||
- [Dapr CLI]({{% ref install-dapr-cli.md %}}) installed
|
||||
- Initialized [Dapr environment]({{% ref install-dapr-selfhost.md %}})
|
||||
- JDK 11 or above - the published jars are compatible with Java 8:
|
||||
- [AdoptOpenJDK 11 - LTS](https://adoptopenjdk.net/)
|
||||
- [Oracle's JDK 15](https://www.oracle.com/java/technologies/javase-downloads.html)
|
||||
|
@ -30,9 +30,9 @@ Dapr offers a variety of packages to help with the development of Java applicati
|
|||
|
||||
Next, import the Java SDK packages to get started. Select your preferred build tool to learn how to import.
|
||||
|
||||
{{< tabs Maven Gradle >}}
|
||||
{{< tabpane text=true >}}
|
||||
|
||||
{{% codetab %}}
|
||||
{{% tab header="Maven" %}}
|
||||
<!--Maven-->
|
||||
|
||||
For a Maven project, add the following to your `pom.xml` file:
|
||||
|
@ -65,9 +65,9 @@ For a Maven project, add the following to your `pom.xml` file:
|
|||
...
|
||||
</project>
|
||||
```
|
||||
{{% /codetab %}}
|
||||
{{% /tab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
{{% tab header="Gradle" %}}
|
||||
<!--Gradle-->
|
||||
|
||||
For a Gradle project, add the following to your `build.gradle` file:
|
||||
|
@ -84,9 +84,9 @@ dependencies {
|
|||
}
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
{{% /tab %}}
|
||||
|
||||
{{< /tabs >}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
If you are also using Spring Boot, you may run into a common issue where the `OkHttp` version that the Dapr SDK uses conflicts with the one specified in the Spring Boot _Bill of Materials_.
|
||||
|
||||
|
@ -106,7 +106,7 @@ Put the Dapr Java SDK to the test. Walk through the Java quickstarts and tutoria
|
|||
|
||||
| SDK samples | Description |
|
||||
| ----------- | ----------- |
|
||||
| [Quickstarts]({{< ref quickstarts >}}) | Experience Dapr's API building blocks in just a few minutes using the Java SDK. |
|
||||
| [Quickstarts]({{% ref quickstarts %}}) | Experience Dapr's API building blocks in just a few minutes using the Java SDK. |
|
||||
| [SDK samples](https://github.com/dapr/java-sdk/tree/master/examples) | Clone the SDK repo to try out some examples and get started. |
|
||||
|
||||
```java
|
||||
|
@ -122,7 +122,7 @@ try (DaprClient client = (new DaprClientBuilder()).build()) {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full guide on output bindings visit [How-To: Output bindings]({{< ref howto-bindings.md >}}).
|
||||
- For a full guide on output bindings visit [How-To: Output bindings]({{% ref howto-bindings.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/bindings/http) for code samples and instructions to try out output bindings.
|
||||
|
||||
## Available packages
|
||||
|
@ -132,14 +132,14 @@ try (DaprClient client = (new DaprClientBuilder()).build()) {
|
|||
<div class="card-body">
|
||||
<h5 class="card-title"><b>Client</b></h5>
|
||||
<p class="card-text">Create Java clients that interact with a Dapr sidecar and other Dapr applications.</p>
|
||||
<a href="{{< ref java-client >}}" class="stretched-link"></a>
|
||||
<a href="{{% ref java-client %}}" class="stretched-link"></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><b>Workflow</b></h5>
|
||||
<p class="card-text">Create and manage workflows that work with other Dapr APIs in Java.</p>
|
||||
<a href="{{< ref workflow >}}" class="stretched-link"></a>
|
||||
<a href="{{% ref workflow %}}" class="stretched-link"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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 %}})
|
|
@ -9,13 +9,13 @@ description: How to get up and running with the Dapr Java SDK
|
|||
The Dapr client package allows you to interact with other Dapr applications from a Java application.
|
||||
|
||||
{{% alert title="Note" color="primary" %}}
|
||||
If you haven't already, [try out one of the quickstarts]({{< ref quickstarts >}}) for a quick walk-through on how to use the Dapr Java SDK with an API building block.
|
||||
If you haven't already, [try out one of the quickstarts]({{% ref quickstarts %}}) for a quick walk-through on how to use the Dapr Java SDK with an API building block.
|
||||
|
||||
{{% /alert %}}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
[Complete initial setup and import the Java SDK into your project]({{< ref java >}})
|
||||
[Complete initial setup and import the Java SDK into your project]({{% ref java %}})
|
||||
|
||||
## Initializing the client
|
||||
You can initialize a Dapr client as so:
|
||||
|
@ -24,21 +24,7 @@ You can initialize a Dapr client as so:
|
|||
DaprClient client = new DaprClientBuilder().build()
|
||||
```
|
||||
|
||||
This will connect to the default Dapr gRPC endpoint `localhost:50001`.
|
||||
|
||||
|
||||
#### Environment variables:
|
||||
|
||||
##### Dapr Sidecar Endpoints
|
||||
You can use the standardized `DAPR_GRPC_ENDPOINT` and `DAPR_HTTP_ENDPOINT` environment variables to
|
||||
specify a different gRPC or HTTP endpoint. When these variables are set, the client will automatically use them to connect to the Dapr sidecar.
|
||||
|
||||
The legacy environment variables `DAPR_HTTP_PORT` and `DAPR_GRPC_PORT` are still supported, but `DAPR_GRPC_ENDPOINT` and `DAPR_HTTP_ENDPOINT` take precedence.
|
||||
|
||||
##### Dapr API Token
|
||||
If your Dapr instance is configured to require the `DAPR_API_TOKEN` environment variable, you can
|
||||
set it in the environment and the client will use it automatically.
|
||||
You can read more about Dapr API token authentication [here](https://docs.dapr.io/operations/security/api-token/).
|
||||
This will connect to the default Dapr gRPC endpoint `localhost:50001`. For information about configuring the client using environment variables and system properties, see [Properties]({{% ref properties.md %}}).
|
||||
|
||||
#### Error Handling
|
||||
|
||||
|
@ -66,7 +52,7 @@ Example of handling the DaprException and consuming the error details when using
|
|||
|
||||
## Building blocks
|
||||
|
||||
The Java SDK allows you to interface with all of the [Dapr building blocks]({{< ref building-blocks >}}).
|
||||
The Java SDK allows you to interface with all of the [Dapr building blocks]({{% ref building-blocks %}}).
|
||||
|
||||
### Invoke a service
|
||||
|
||||
|
@ -90,7 +76,7 @@ try (DaprClient client = (new DaprClientBuilder()).build()) {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full guide on service invocation visit [How-To: Invoke a service]({{< ref howto-invoke-discover-services.md >}}).
|
||||
- For a full guide on service invocation visit [How-To: Invoke a service]({{% ref howto-invoke-discover-services.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/invoke) for code samples and instructions to try out service invocation
|
||||
|
||||
### Save & get application state
|
||||
|
@ -113,7 +99,7 @@ try (DaprClient client = (new DaprClientBuilder()).build()) {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full list of state operations visit [How-To: Get & save state]({{< ref howto-get-save-state.md >}}).
|
||||
- For a full list of state operations visit [How-To: Get & save state]({{% ref howto-get-save-state.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/state) for code samples and instructions to try out state management
|
||||
|
||||
### Publish & subscribe to messages
|
||||
|
@ -239,7 +225,7 @@ class Solution {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full guide on publishing messages and subscribing to a topic [How-To: Publish & subscribe]({{< ref howto-publish-subscribe.md >}}).
|
||||
- For a full guide on publishing messages and subscribing to a topic [How-To: Publish & subscribe]({{% ref howto-publish-subscribe.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/pubsub/http) for code samples and instructions to try out pub/sub
|
||||
|
||||
### Interact with output bindings
|
||||
|
@ -257,7 +243,7 @@ try (DaprClient client = (new DaprClientBuilder()).build()) {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full guide on output bindings visit [How-To: Output bindings]({{< ref howto-bindings.md >}}).
|
||||
- For a full guide on output bindings visit [How-To: Output bindings]({{% ref howto-bindings.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/bindings/http) for code samples and instructions to try out output bindings.
|
||||
|
||||
### Interact with input bindings
|
||||
|
@ -279,7 +265,7 @@ public class myClass {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full guide on input bindings, visit [How-To: Input bindings]({{< ref howto-triggers >}}).
|
||||
- For a full guide on input bindings, visit [How-To: Input bindings]({{% ref howto-triggers %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/bindings/http) for code samples and instructions to try out input bindings.
|
||||
|
||||
### Retrieve secrets
|
||||
|
@ -296,7 +282,7 @@ try (DaprClient client = (new DaprClientBuilder()).build()) {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full guide on secrets visit [How-To: Retrieve secrets]({{< ref howto-secrets.md >}}).
|
||||
- For a full guide on secrets visit [How-To: Retrieve secrets]({{% ref howto-secrets.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/secrets) for code samples and instructions to try out retrieving secrets
|
||||
|
||||
### Actors
|
||||
|
@ -322,7 +308,7 @@ public interface DemoActor {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full guide on actors visit [How-To: Use virtual actors in Dapr]({{< ref howto-actors.md >}}).
|
||||
- For a full guide on actors visit [How-To: Use virtual actors in Dapr]({{% ref howto-actors.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/actors) for code samples and instructions to try actors
|
||||
|
||||
### Get & Subscribe to application configurations
|
||||
|
@ -355,7 +341,7 @@ try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient())
|
|||
}
|
||||
```
|
||||
|
||||
- For a full list of configuration operations visit [How-To: Manage configuration from a store]({{< ref howto-manage-configuration.md >}}).
|
||||
- For a full list of configuration operations visit [How-To: Manage configuration from a store]({{% ref howto-manage-configuration.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/configuration) for code samples and instructions to try out different configuration operations.
|
||||
|
||||
### Query saved state
|
||||
|
@ -425,7 +411,7 @@ try (DaprClient client = builder.build(); DaprPreviewClient previewClient = buil
|
|||
}
|
||||
}
|
||||
```
|
||||
- For a full how-to on query state, visit [How-To: Query state]({{< ref howto-state-query-api.md >}}).
|
||||
- For a full how-to on query state, visit [How-To: Query state]({{% ref howto-state-query-api.md %}}).
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/querystate) for complete code sample.
|
||||
|
||||
### Distributed lock
|
||||
|
@ -491,7 +477,7 @@ public class DistributedLockGrpcClient {
|
|||
}
|
||||
```
|
||||
|
||||
- For a full how-to on distributed lock, visit [How-To: Use a Lock]({{< ref howto-use-distributed-lock.md >}})
|
||||
- For a full how-to on distributed lock, visit [How-To: Use a Lock]({{% ref howto-use-distributed-lock.md %}})
|
||||
- Visit [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/lock) for complete code sample.
|
||||
|
||||
### Workflow
|
||||
|
@ -612,9 +598,9 @@ public class DemoWorkflowClient {
|
|||
```
|
||||
|
||||
- For a full guide on workflows, visit:
|
||||
- [How-To: Author workflows]({{< ref howto-author-workflow.md >}}).
|
||||
- [How-To: Manage workflows]({{< ref howto-manage-workflow.md >}}).
|
||||
- [Learn more about how to use workflows with the Java SDK]({{< ref java-workflow.md >}}).
|
||||
- [How-To: Author workflows]({{% ref howto-author-workflow.md %}}).
|
||||
- [How-To: Manage workflows]({{% ref howto-manage-workflow.md %}}).
|
||||
- [Learn more about how to use workflows with the Java SDK]({{% ref java-workflow.md %}}).
|
||||
|
||||
## Sidecar APIs
|
||||
|
||||
|
@ -648,3 +634,5 @@ Learn more about the [Dapr Java SDK packages available to add to your Java appli
|
|||
|
||||
## Related links
|
||||
- [Java SDK examples](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples)
|
||||
|
||||
For a full list of SDK properties and how to configure them, visit [Properties]({{% ref properties.md %}}).
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
---
|
||||
type: docs
|
||||
title: "Properties"
|
||||
linkTitle: "Properties"
|
||||
weight: 3001
|
||||
description: SDK-wide properties for configuring the Dapr Java SDK using environment variables and system properties
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
The Dapr Java SDK provides a set of global properties that control the behavior of the SDK. These properties can be configured using environment variables or system properties. System properties can be set using the `-D` flag when running your Java application.
|
||||
|
||||
These properties affect the entire SDK, including clients and runtime. They control aspects such as:
|
||||
- Sidecar connectivity (endpoints, ports)
|
||||
- Security settings (TLS, API tokens)
|
||||
- Performance tuning (timeouts, connection pools)
|
||||
- Protocol settings (gRPC, HTTP)
|
||||
- String encoding
|
||||
|
||||
## Environment Variables
|
||||
|
||||
The following environment variables are available for configuring the Dapr Java SDK:
|
||||
|
||||
### Sidecar Endpoints
|
||||
|
||||
When these variables are set, the client will automatically use them to connect to the Dapr sidecar.
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---------------------|-------------|---------|
|
||||
| `DAPR_GRPC_ENDPOINT` | The gRPC endpoint for the Dapr sidecar | `localhost:50001` |
|
||||
| `DAPR_HTTP_ENDPOINT` | The HTTP endpoint for the Dapr sidecar | `localhost:3500` |
|
||||
| `DAPR_GRPC_PORT` | The gRPC port for the Dapr sidecar (legacy, `DAPR_GRPC_ENDPOINT` takes precedence) | `50001` |
|
||||
| `DAPR_HTTP_PORT` | The HTTP port for the Dapr sidecar (legacy, `DAPR_HTTP_ENDPOINT` takes precedence) | `3500` |
|
||||
|
||||
### API Token
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---------------------|-------------|---------|
|
||||
| `DAPR_API_TOKEN` | API token for authentication between app and Dapr sidecar. This is the same token used by the Dapr runtime for API authentication. For more details, see [Dapr API token authentication](https://docs.dapr.io/operations/security/api-token/) and [Environment variables reference](https://docs.dapr.io/reference/environment/#dapr_api_token). | `null` |
|
||||
|
||||
### gRPC Configuration
|
||||
|
||||
#### TLS Settings
|
||||
For secure gRPC communication, you can configure TLS settings using the following environment variables:
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---------------------|-------------|---------|
|
||||
| `DAPR_GRPC_TLS_INSECURE` | When set to "true", enables insecure TLS mode which still uses TLS but doesn't verify certificates. This uses InsecureTrustManagerFactory to trust all certificates. This should only be used for testing or in secure environments. | `false` |
|
||||
| `DAPR_GRPC_TLS_CA_PATH` | Path to the CA certificate file. This is used for TLS connections to servers with self-signed certificates. | `null` |
|
||||
| `DAPR_GRPC_TLS_CERT_PATH` | Path to the TLS certificate file for client authentication. | `null` |
|
||||
| `DAPR_GRPC_TLS_KEY_PATH` | Path to the TLS private key file for client authentication. | `null` |
|
||||
|
||||
#### Keepalive Settings
|
||||
Configure gRPC keepalive behavior using these environment variables:
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---------------------|-------------|---------|
|
||||
| `DAPR_GRPC_ENABLE_KEEP_ALIVE` | Whether to enable gRPC keepalive | `false` |
|
||||
| `DAPR_GRPC_KEEP_ALIVE_TIME_SECONDS` | gRPC keepalive time in seconds | `10` |
|
||||
| `DAPR_GRPC_KEEP_ALIVE_TIMEOUT_SECONDS` | gRPC keepalive timeout in seconds | `5` |
|
||||
| `DAPR_GRPC_KEEP_ALIVE_WITHOUT_CALLS` | Whether to keep gRPC connection alive without calls | `true` |
|
||||
|
||||
### HTTP Client Configuration
|
||||
|
||||
These properties control the behavior of the HTTP client used for communication with the Dapr sidecar:
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---------------------|-------------|---------|
|
||||
| `DAPR_HTTP_CLIENT_READ_TIMEOUT_SECONDS` | Timeout in seconds for HTTP client read operations. This is the maximum time to wait for a response from the Dapr sidecar. | `60` |
|
||||
| `DAPR_HTTP_CLIENT_MAX_REQUESTS` | Maximum number of concurrent HTTP requests that can be executed. Above this limit, requests will queue in memory waiting for running calls to complete. | `1024` |
|
||||
| `DAPR_HTTP_CLIENT_MAX_IDLE_CONNECTIONS` | Maximum number of idle connections in the HTTP connection pool. This is the maximum number of connections that can remain idle in the pool. | `128` |
|
||||
|
||||
### API Configuration
|
||||
|
||||
These properties control the behavior of API calls made through the SDK:
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---------------------|-------------|---------|
|
||||
| `DAPR_API_MAX_RETRIES` | Maximum number of retries for retriable exceptions when making API calls to the Dapr sidecar | `0` |
|
||||
| `DAPR_API_TIMEOUT_MILLISECONDS` | Timeout in milliseconds for API calls to the Dapr sidecar. A value of 0 means no timeout. | `0` |
|
||||
|
||||
### String Encoding
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---------------------|-------------|---------|
|
||||
| `DAPR_STRING_CHARSET` | Character set used for string encoding/decoding in the SDK. Must be a valid Java charset name. | `UTF-8` |
|
||||
|
||||
### System Properties
|
||||
|
||||
All environment variables can be set as system properties using the `-D` flag. Here is the complete list of available system properties:
|
||||
|
||||
| System Property | Description | Default |
|
||||
|----------------|-------------|---------|
|
||||
| `dapr.sidecar.ip` | IP address for the Dapr sidecar | `localhost` |
|
||||
| `dapr.http.port` | HTTP port for the Dapr sidecar | `3500` |
|
||||
| `dapr.grpc.port` | gRPC port for the Dapr sidecar | `50001` |
|
||||
| `dapr.grpc.tls.cert.path` | Path to the gRPC TLS certificate | `null` |
|
||||
| `dapr.grpc.tls.key.path` | Path to the gRPC TLS key | `null` |
|
||||
| `dapr.grpc.tls.ca.path` | Path to the gRPC TLS CA certificate | `null` |
|
||||
| `dapr.grpc.tls.insecure` | Whether to use insecure TLS mode | `false` |
|
||||
| `dapr.grpc.endpoint` | gRPC endpoint for remote sidecar | `null` |
|
||||
| `dapr.grpc.enable.keep.alive` | Whether to enable gRPC keepalive | `false` |
|
||||
| `dapr.grpc.keep.alive.time.seconds` | gRPC keepalive time in seconds | `10` |
|
||||
| `dapr.grpc.keep.alive.timeout.seconds` | gRPC keepalive timeout in seconds | `5` |
|
||||
| `dapr.grpc.keep.alive.without.calls` | Whether to keep gRPC connection alive without calls | `true` |
|
||||
| `dapr.http.endpoint` | HTTP endpoint for remote sidecar | `null` |
|
||||
| `dapr.api.maxRetries` | Maximum number of retries for API calls | `0` |
|
||||
| `dapr.api.timeoutMilliseconds` | Timeout for API calls in milliseconds | `0` |
|
||||
| `dapr.api.token` | API token for authentication | `null` |
|
||||
| `dapr.string.charset` | String encoding used in the SDK | `UTF-8` |
|
||||
| `dapr.http.client.readTimeoutSeconds` | Timeout in seconds for HTTP client reads | `60` |
|
||||
| `dapr.http.client.maxRequests` | Maximum number of concurrent HTTP requests | `1024` |
|
||||
| `dapr.http.client.maxIdleConnections` | Maximum number of idle HTTP connections | `128` |
|
||||
|
||||
## Property Resolution Order
|
||||
|
||||
Properties are resolved in the following order:
|
||||
1. Override values (if provided when creating a Properties instance)
|
||||
2. System properties (set via `-D`)
|
||||
3. Environment variables
|
||||
4. Default values
|
||||
|
||||
The SDK checks each source in order. If a value is invalid for the property type (e.g., non-numeric for a numeric property), the SDK will log a warning and try the next source. For example:
|
||||
|
||||
```bash
|
||||
# Invalid boolean value - will be ignored
|
||||
java -Ddapr.grpc.enable.keep.alive=not-a-boolean -jar myapp.jar
|
||||
|
||||
# Valid boolean value - will be used
|
||||
export DAPR_GRPC_ENABLE_KEEP_ALIVE=false
|
||||
```
|
||||
|
||||
In this case, the environment variable is used because the system property value is invalid. However, if both values are valid, the system property takes precedence:
|
||||
|
||||
```bash
|
||||
# Valid boolean value - will be used
|
||||
java -Ddapr.grpc.enable.keep.alive=true -jar myapp.jar
|
||||
|
||||
# Valid boolean value - will be ignored
|
||||
export DAPR_GRPC_ENABLE_KEEP_ALIVE=false
|
||||
```
|
||||
|
||||
Override values can be set using the `DaprClientBuilder` in two ways:
|
||||
|
||||
1. Using individual property overrides (recommended for most cases):
|
||||
```java
|
||||
import io.dapr.config.Properties;
|
||||
|
||||
// Set a single property override
|
||||
DaprClient client = new DaprClientBuilder()
|
||||
.withPropertyOverride(Properties.GRPC_ENABLE_KEEP_ALIVE, "true")
|
||||
.build();
|
||||
|
||||
// Or set multiple property overrides
|
||||
DaprClient client = new DaprClientBuilder()
|
||||
.withPropertyOverride(Properties.GRPC_ENABLE_KEEP_ALIVE, "true")
|
||||
.withPropertyOverride(Properties.HTTP_CLIENT_READ_TIMEOUT_SECONDS, "120")
|
||||
.build();
|
||||
```
|
||||
|
||||
2. Using a Properties instance (useful when you have many properties to set at once):
|
||||
```java
|
||||
// Create a map of property overrides
|
||||
Map<String, String> overrides = new HashMap<>();
|
||||
overrides.put("dapr.grpc.enable.keep.alive", "true");
|
||||
overrides.put("dapr.http.client.readTimeoutSeconds", "120");
|
||||
|
||||
// Create a Properties instance with overrides
|
||||
Properties properties = new Properties(overrides);
|
||||
|
||||
// Use these properties when creating a client
|
||||
DaprClient client = new DaprClientBuilder()
|
||||
.withProperties(properties)
|
||||
.build();
|
||||
```
|
||||
|
||||
For most use cases, you'll use system properties or environment variables. Override values are primarily used when you need different property values for different instances of the SDK in the same application.
|
||||
|
||||
## Proxy Configuration
|
||||
|
||||
You can configure proxy settings for your Java application using system properties. These are standard Java system properties that are part of Java's networking layer (`java.net` package), not specific to Dapr. They are used by Java's networking stack, including the HTTP client that Dapr's SDK uses.
|
||||
|
||||
For detailed information about Java's proxy configuration, including all available properties and their usage, see the [Java Networking Properties documentation](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/doc-files/net-properties.html).
|
||||
|
||||
|
||||
For example, here's how to configure a proxy:
|
||||
|
||||
```bash
|
||||
# Configure HTTP proxy - replace with your actual proxy server details
|
||||
java -Dhttp.proxyHost=your-proxy-server.com -Dhttp.proxyPort=8080 -jar myapp.jar
|
||||
|
||||
# Configure HTTPS proxy - replace with your actual proxy server details
|
||||
java -Dhttps.proxyHost=your-proxy-server.com -Dhttps.proxyPort=8443 -jar myapp.jar
|
||||
```
|
||||
|
||||
Replace `your-proxy-server.com` with your actual proxy server hostname or IP address, and adjust the port numbers to match your proxy server configuration.
|
||||
|
||||
These proxy settings will affect all HTTP/HTTPS connections made by your Java application, including connections to the Dapr sidecar.
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
type: docs
|
||||
title: "Jobs"
|
||||
linkTitle: "Jobs"
|
||||
weight: 3000
|
||||
description: With the Dapr Jobs package, you can interact with the Dapr Jobs APIs from a Java application to trigger future operations to run according to a predefined schedule with an optional payload. To get started, walk through the [Dapr Jobs]({{% ref java-jobs-howto.md %}}) how-to guide.
|
||||
---
|
|
@ -0,0 +1,164 @@
|
|||
---
|
||||
type: docs
|
||||
title: "How to: Author and manage Dapr Jobs in the Java SDK"
|
||||
linkTitle: "How to: Author and manage Jobs"
|
||||
weight: 20000
|
||||
description: How to get up and running with Jobs using the Dapr Java SDK
|
||||
---
|
||||
|
||||
As part of this demonstration we will schedule a Dapr Job. The scheduled job will trigger an endpoint registered in the
|
||||
same app. With the [provided jobs example](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/jobs), you will:
|
||||
|
||||
- Schedule a Job [Job scheduling example](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java)
|
||||
- Register an endpoint for the dapr sidecar to invoke at trigger time [Endpoint Registration](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/jobs/DemoJobsSpringApplication.java)
|
||||
|
||||
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 jobs 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 jobsapp --dapr-grpc-port 51439 --dapr-http-port 3500 --app-port 8080
|
||||
```
|
||||
|
||||
> Now, Dapr is listening for HTTP requests at `http://localhost:3500` and internal Jobs gRPC requests at `http://localhost:51439`.
|
||||
|
||||
## Schedule and Get a job
|
||||
|
||||
In the `DemoJobsClient` there are steps to schedule a job. Calling `scheduleJob` using the `DaprPreviewClient`
|
||||
will schedule a job with the Dapr Runtime.
|
||||
|
||||
```java
|
||||
public class DemoJobsClient {
|
||||
|
||||
/**
|
||||
* The main method of this app to schedule and get jobs.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) {
|
||||
|
||||
// Schedule a job.
|
||||
System.out.println("**** Scheduling a Job with name dapr-jobs-1 *****");
|
||||
ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("dapr-job-1",
|
||||
JobSchedule.fromString("* * * * * *")).setData("Hello World!".getBytes());
|
||||
client.scheduleJob(scheduleJobRequest).block();
|
||||
|
||||
System.out.println("**** Scheduling job dapr-jobs-1 completed *****");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Call `getJob` to retrieve the job details that were previously created and scheduled.
|
||||
```
|
||||
client.getJob(new GetJobRequest("dapr-job-1")).block()
|
||||
```
|
||||
|
||||
Run the `DemoJobsClient` with the following command.
|
||||
|
||||
```sh
|
||||
java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsClient
|
||||
```
|
||||
|
||||
### Sample output
|
||||
```
|
||||
**** Scheduling a Job with name dapr-jobs-1 *****
|
||||
**** Scheduling job dapr-jobs-1 completed *****
|
||||
**** Retrieving a Job with name dapr-jobs-1 *****
|
||||
```
|
||||
|
||||
## Set up an endpoint to be invoked when the job is triggered
|
||||
|
||||
The `DemoJobsSpringApplication` class starts a Spring Boot application that registers the endpoints specified in the `JobsController`
|
||||
This endpoint acts like a callback for the scheduled job requests.
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class JobsController {
|
||||
|
||||
/**
|
||||
* Handles jobs callback from Dapr.
|
||||
*
|
||||
* @param jobName name of the job.
|
||||
* @param payload data from the job if payload exists.
|
||||
* @return Empty Mono.
|
||||
*/
|
||||
@PostMapping("/job/{jobName}")
|
||||
public Mono<Void> handleJob(@PathVariable("jobName") String jobName,
|
||||
@RequestBody(required = false) byte[] payload) {
|
||||
System.out.println("Job Name: " + jobName);
|
||||
System.out.println("Job Payload: " + new String(payload));
|
||||
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
* `jobName`: The name of the triggered job.
|
||||
* `payload`: Optional payload data associated with the job (as a byte array).
|
||||
|
||||
Run the Spring Boot application with the following command.
|
||||
|
||||
```sh
|
||||
java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsSpringApplication
|
||||
```
|
||||
|
||||
### Sample output
|
||||
```
|
||||
Job Name: dapr-job-1
|
||||
Job Payload: Hello World!
|
||||
```
|
||||
|
||||
## Delete a scheduled job
|
||||
|
||||
```java
|
||||
public class DemoJobsClient {
|
||||
|
||||
/**
|
||||
* The main method of this app deletes a job that was previously scheduled.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (DaprPreviewClient client = new DaprClientBuilder().buildPreviewClient()) {
|
||||
|
||||
// Delete a job.
|
||||
System.out.println("**** Delete a Job with name dapr-jobs-1 *****");
|
||||
client.deleteJob(new DeleteJobRequest("dapr-job-1")).block();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Next steps
|
||||
- [Learn more about Jobs]({{% ref jobs-overview.md %}})
|
||||
- [Jobs API reference]({{% ref jobs_api.md %}})
|
|
@ -245,5 +245,5 @@ Exiting DemoWorkflowClient.
|
|||
1. The worfklow client is then exited.
|
||||
|
||||
## Next steps
|
||||
- [Learn more about Dapr workflow]({{< ref workflow-overview.md >}})
|
||||
- [Workflow API reference]({{< ref workflow_api.md >}})
|
||||
- [Learn more about Dapr workflow]({{% ref workflow-overview.md %}})
|
||||
- [Workflow API reference]({{% ref workflow_api.md %}})
|
|
@ -8,34 +8,37 @@ description: How to get started with Dapr and Spring Boot
|
|||
|
||||
By combining Dapr and Spring Boot, we can create infrastructure independent Java applications that can be deployed across different environments, supporting a wide range of on-premises and cloud provider services.
|
||||
|
||||
First, we will start with a simple integration covering the `DaprClient` and the [Testcontainers](https://testcontainers.com/) integration, to then use Spring and Spring Boot mechanisms and programming model to leverage the Dapr APIs under the hood. This help teams to remove dependencies such as clients and drivers required to connect to environment specific infrastructure (databases, key-value stores, message brokers, configuration/secret stores, etc.)
|
||||
First, we will start with a simple integration covering the `DaprClient` and the [Testcontainers](https://testcontainers.com/) integration, to then use Spring and Spring Boot mechanisms and programming model to leverage the Dapr APIs under the hood. This helps teams to remove dependencies such as clients and drivers required to connect to environment-specific infrastructure (databases, key-value stores, message brokers, configuration/secret stores, etc)
|
||||
|
||||
{{% alert title="Note" color="primary" %}}
|
||||
The Spring Boot integration explained in this page is still alpha, hence most artifacts are labeled with 0.13.0.
|
||||
The Spring Boot integration requires Spring Boot 3.x+ to work. This will not work with Spring Boot 2.x.
|
||||
The Spring Boot integration remains in alpha. We need your help and feedback to graduate it.
|
||||
Please join the [#java-sdk discord channel](https://discord.com/channels/778680217417809931/778749797242765342) discussion or open issues in the [dapr/java-sdk](https://github.com/dapr/java-sdk/issues).
|
||||
|
||||
{{% /alert %}}
|
||||
|
||||
|
||||
## Adding the Dapr and Spring Boot integration to your project
|
||||
|
||||
If you already have a Spring Boot application (Spring Boot 3.x+), you can directly add the following dependencies to your project:
|
||||
|
||||
If you already have a Spring Boot application, you can directly add the following dependencies to your project:
|
||||
|
||||
```
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-starter</artifactId>
|
||||
<version>0.14.1</version>
|
||||
<version>0.x.x</version> // see below for the latest versions
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-starter-test</artifactId>
|
||||
<version>0.14.1</version>
|
||||
<version>0.x.x</version> // see below for the latest versions
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
By adding these dependencies you can:
|
||||
You can find the [latest released version here](https://central.sonatype.com/artifact/io.dapr.spring/dapr-spring-boot-starter).
|
||||
|
||||
By adding these dependencies, you can:
|
||||
- Autowire a `DaprClient` to use inside your applications
|
||||
- Use the Spring Data and Messaging abstractions and programming model that uses the Dapr APIs under the hood
|
||||
- Improve your inner-development loop by relying on [Testcontainers](https://testcontainers.com/) to bootstrap Dapr Control plane services and default components
|
||||
|
@ -50,6 +53,18 @@ private DaprClient daprClient;
|
|||
|
||||
This will connect to the default Dapr gRPC endpoint `localhost:50001`, requiring you to start Dapr outside of your application.
|
||||
|
||||
{{% alert title="Note" color="primary" %}}
|
||||
By default, the following properties are preconfigured for `DaprClient` and `DaprWorkflowClient`:
|
||||
```properties
|
||||
dapr.client.http-endpoint=http://localhost
|
||||
dapr.client.http-port=3500
|
||||
dapr.client.grpc-endpoint=localhost
|
||||
dapr.client.grpc-port=50001
|
||||
dapr.client.api-token=<Your Remote App API Token>
|
||||
```
|
||||
These values are used by default, but you can override them in your `application.properties` file to suit your environment.
|
||||
{{% /alert %}}
|
||||
|
||||
You can use the `DaprClient` to interact with the Dapr APIs anywhere in your application, for example from inside a REST endpoint:
|
||||
|
||||
```java
|
||||
|
@ -67,10 +82,10 @@ public class DemoRestController {
|
|||
record Order(String orderId, Integer amount){}
|
||||
```
|
||||
|
||||
If you want to avoid managing Dapr outside of your Spring Boot application, you can rely on [Testcontainers](https://testcontainers.com/) to bootstrap Dapr besides your application for development purposes.
|
||||
If you want to avoid managing Dapr outside of your Spring Boot application, you can rely on [Testcontainers](https://testcontainers.com/) to bootstrap Dapr beside your application for development purposes.
|
||||
To do this we can create a test configuration that uses `Testcontainers` to bootstrap all we need to develop our applications using the Dapr APIs.
|
||||
|
||||
Using [Testcontaniners](https://testcontainers.com/) and Dapr integrations, we let the `@TestConfiguration` to bootstrap Dapr for our applications.
|
||||
Using [Testcontainers](https://testcontainers.com/) and Dapr integrations, we let the `@TestConfiguration` bootstrap Dapr for our applications.
|
||||
Notice that for this example, we are configuring Dapr with a Statestore component called `kvstore` that connects to an instance of `PostgreSQL` also bootstrapped by Testcontainers.
|
||||
|
||||
```java
|
||||
|
@ -80,7 +95,7 @@ public class DaprTestContainersConfig {
|
|||
@ServiceConnection
|
||||
public DaprContainer daprContainer(Network daprNetwork, PostgreSQLContainer<?> postgreSQLContainer){
|
||||
|
||||
return new DaprContainer("daprio/daprd:1.14.1")
|
||||
return new DaprContainer("daprio/daprd:1.15.7")
|
||||
.withAppName("producer-app")
|
||||
.withNetwork(daprNetwork)
|
||||
.withComponent(new Component("kvstore", "state.postgresql", "v1", STATE_STORE_PROPERTIES))
|
||||
|
@ -119,7 +134,7 @@ Besides the previous configuration (`DaprTestContainersConfig`) your tests shoul
|
|||
|
||||
## Leveraging Spring & Spring Boot programming model with Dapr
|
||||
|
||||
The Java SDK allows you to interface with all of the [Dapr building blocks]({{< ref building-blocks >}}).
|
||||
The Java SDK allows you to interface with all of the [Dapr building blocks]({{% ref building-blocks %}}).
|
||||
But if you want to leverage the Spring and Spring Boot programming model you can use the `dapr-spring-boot-starter` integration.
|
||||
This includes implementations of Spring Data (`KeyValueTemplate` and `CrudRepository`) as well as a `DaprMessagingTemplate` for producing and consuming messages
|
||||
(similar to [Spring Kafka](https://spring.io/projects/spring-kafka), [Spring Pulsar](https://spring.io/projects/spring-pulsar) and [Spring AMQP for RabbitMQ](https://spring.io/projects/spring-amqp)) and Dapr workflows.
|
||||
|
@ -170,7 +185,7 @@ Where `OrderRepository` is defined in an interface that extends the Spring Data
|
|||
public interface OrderRepository extends CrudRepository<Order, String> {}
|
||||
```
|
||||
|
||||
Notice that the `@EnableDaprRepositories` annotation, does all the magic of wiring the Dapr APIs under the `CrudRespository` interface.
|
||||
Notice that the `@EnableDaprRepositories` annotation does all the magic of wiring the Dapr APIs under the `CrudRespository` interface.
|
||||
Because Dapr allow users to interact with different StateStores from the same application, as a user you need to provide the following beans as a Spring Boot `@Configuration`:
|
||||
|
||||
```java
|
||||
|
@ -235,7 +250,7 @@ Finally, because Dapr PubSub requires a bidirectional connection between your ap
|
|||
@ServiceConnection
|
||||
public DaprContainer daprContainer(Network daprNetwork, PostgreSQLContainer<?> postgreSQLContainer, RabbitMQContainer rabbitMQContainer){
|
||||
|
||||
return new DaprContainer("daprio/daprd:1.14.1")
|
||||
return new DaprContainer("daprio/daprd:1.15.7")
|
||||
.withAppName("producer-app")
|
||||
.withNetwork(daprNetwork)
|
||||
.withComponent(new Component("kvstore", "state.postgresql", "v1", STATE_STORE_PROPERTIES))
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: echo
|
||||
spec:
|
||||
type: conversation.echo
|
||||
version: v1
|
|
@ -7,12 +7,12 @@
|
|||
<parent>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-parent</artifactId>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-sdk-examples</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
<name>dapr-sdk-examples</name>
|
||||
|
||||
<properties>
|
||||
|
@ -22,14 +22,15 @@
|
|||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
<spotbugs.fail>false</spotbugs.fail>
|
||||
<opentelemetry.version>0.14.0</opentelemetry.version>
|
||||
<opentelemetry.version>1.41.0</opentelemetry.version>
|
||||
<zipkin.version>3.4.0</zipkin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
|
@ -77,11 +78,26 @@
|
|||
<artifactId>opentelemetry-exporter-logging</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk-metrics</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-exporter-zipkin</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-reporter</artifactId>
|
||||
<version>${zipkin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-urlconnection</artifactId>
|
||||
<version>${zipkin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
|
@ -133,11 +149,6 @@
|
|||
<artifactId>protobuf-java</artifactId>
|
||||
<version>${protobuf.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.12.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -23,7 +23,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||
public class DaprApplication {
|
||||
|
||||
/**
|
||||
* Starts Dapr's callback in a given port and specified protocal.
|
||||
* Starts Dapr's callback in a given port and specified protocol.
|
||||
*
|
||||
* @param port Port to listen to.
|
||||
* @param protocal select Http or gRPC to run.
|
||||
|
|
|
@ -20,9 +20,10 @@ import io.opentelemetry.api.trace.Tracer;
|
|||
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.ContextPropagators;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import io.opentelemetry.context.propagation.TextMapSetter;
|
||||
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
||||
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -59,18 +60,23 @@ public class OpenTelemetryConfig {
|
|||
* Creates an opentelemetry instance.
|
||||
* @return OpenTelemetry.
|
||||
*/
|
||||
public static OpenTelemetry createOpenTelemetry() {
|
||||
public static OpenTelemetrySdk createOpenTelemetry() {
|
||||
// Only exports to Zipkin if it is up. Otherwise, ignore it.
|
||||
// This is helpful to avoid exceptions for examples that do not require Zipkin.
|
||||
if (isZipkinUp()) {
|
||||
Resource serviceResource = Resource.getDefault()
|
||||
.toBuilder()
|
||||
.put("service.name", InvokeClient.class.getName()) // Use ResourceAttributes constant
|
||||
.build();
|
||||
String httpUrl = String.format("http://localhost:%d", ZIPKIN_PORT);
|
||||
|
||||
ZipkinSpanExporter zipkinExporter =
|
||||
ZipkinSpanExporter.builder()
|
||||
.setEndpoint(httpUrl + ENDPOINT_V2_SPANS)
|
||||
.setServiceName(InvokeClient.class.getName())
|
||||
.build();
|
||||
|
||||
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
|
||||
.setResource(serviceResource)
|
||||
.addSpanProcessor(SimpleSpanProcessor.create(zipkinExporter))
|
||||
.build();
|
||||
|
||||
|
@ -100,7 +106,7 @@ public class OpenTelemetryConfig {
|
|||
*/
|
||||
public static reactor.util.context.Context getReactorContext(Context context) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
TextMapPropagator.Setter<Map<String, String>> setter =
|
||||
TextMapSetter<Map<String, String>> setter =
|
||||
(carrier, key, value) -> map.put(key, value);
|
||||
|
||||
GlobalOpenTelemetry.getPropagators().getTextMapPropagator().inject(context, map, setter);
|
||||
|
|
|
@ -15,6 +15,7 @@ package io.dapr.examples;
|
|||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapGetter;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
@ -34,8 +35,8 @@ public class OpenTelemetryInterceptor implements HandlerInterceptor {
|
|||
@Autowired
|
||||
private OpenTelemetry openTelemetry;
|
||||
|
||||
private static final TextMapPropagator.Getter<HttpServletRequest> HTTP_SERVLET_REQUEST_GETTER =
|
||||
new TextMapPropagator.Getter<>() {
|
||||
private static final TextMapGetter<HttpServletRequest> HTTP_SERVLET_REQUEST_GETTER =
|
||||
new TextMapGetter<>() {
|
||||
@Override
|
||||
public Iterable<String> keys(HttpServletRequest carrier) {
|
||||
return Collections.list(carrier.getHeaderNames());
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2021 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.conversation;
|
||||
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.DaprPreviewClient;
|
||||
import io.dapr.client.domain.ConversationInput;
|
||||
import io.dapr.client.domain.ConversationRequest;
|
||||
import io.dapr.client.domain.ConversationResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
## Manage Dapr via the Conversation API
|
||||
|
||||
This example provides the different capabilities provided by Dapr Java SDK for Conversation. For further information about Conversation APIs please refer to [this link](https://docs.dapr.io/developing-applications/building-blocks/conversation/conversation-overview/)
|
||||
|
||||
### Using the Conversation API
|
||||
|
||||
The Java SDK exposes several methods for this -
|
||||
* `client.converse(...)` for conversing with an LLM through Dapr.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
* [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/).
|
||||
* Java JDK 11 (or greater):
|
||||
* [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11)
|
||||
* [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11)
|
||||
* [OpenJDK 11](https://jdk.java.net/11/)
|
||||
* [Apache Maven](https://maven.apache.org/install.html) version 3.x.
|
||||
|
||||
### Checking out the code
|
||||
|
||||
Clone this repository:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/dapr/java-sdk.git
|
||||
cd java-sdk
|
||||
```
|
||||
|
||||
Then build the Maven project:
|
||||
|
||||
```sh
|
||||
# make sure you are in the `java-sdk` directory
|
||||
mvn install
|
||||
```
|
||||
|
||||
Then get into the examples directory:
|
||||
|
||||
```sh
|
||||
cd examples
|
||||
```
|
||||
|
||||
### Initialize Dapr
|
||||
|
||||
Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized.
|
||||
|
||||
### Running the example
|
||||
|
||||
This example uses the Java SDK Dapr client in order to **Converse** with an LLM.
|
||||
`DemoConversationAI.java` is the example class demonstrating these features.
|
||||
Kindly check [DaprPreviewClient.java](https://github.com/dapr/java-sdk/blob/master/sdk/src/main/java/io/dapr/client/DaprPreviewClient.java) for a detailed description of the supported APIs.
|
||||
|
||||
```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.getConversationOutpus().get(0).getResult());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use the following command to run this example-
|
||||
|
||||
<!-- STEP
|
||||
name: Run Demo Conversation Client example
|
||||
expected_stdout_lines:
|
||||
- "== APP == Conversation output: Hello How are you? This is the my number <ISBN>"
|
||||
background: true
|
||||
output_match_mode: substring
|
||||
sleep: 10
|
||||
-->
|
||||
|
||||
```bash
|
||||
dapr run --resources-path ./components/conversation --app-id myapp --app-port 8080 --dapr-http-port 3500 --dapr-grpc-port 51439 --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.conversation.DemoConversationAI
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
||||
### Sample output
|
||||
```
|
||||
== APP == Conversation output: Hello How are you? This is the my number <ISBN>
|
||||
```
|
||||
### Cleanup
|
||||
|
||||
To stop the app, run (or press CTRL+C):
|
||||
|
||||
<!-- STEP
|
||||
|
||||
name: Cleanup
|
||||
-->
|
||||
|
||||
```bash
|
||||
dapr stop --app-id myapp
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2021 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.jobs;
|
||||
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.DaprPreviewClient;
|
||||
import io.dapr.client.domain.GetJobRequest;
|
||||
import io.dapr.client.domain.GetJobResponse;
|
||||
import io.dapr.client.domain.JobSchedule;
|
||||
import io.dapr.client.domain.ScheduleJobRequest;
|
||||
import io.dapr.config.Properties;
|
||||
import io.dapr.config.Property;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class DemoJobsClient {
|
||||
|
||||
/**
|
||||
* The main method of this app to register and fetch jobs.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Map<Property<?>, String> overrides = Map.of(
|
||||
Properties.HTTP_PORT, "3500",
|
||||
Properties.GRPC_PORT, "51439"
|
||||
);
|
||||
|
||||
try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) {
|
||||
|
||||
// Schedule a job.
|
||||
System.out.println("**** Scheduling a Job with name dapr-jobs-1 *****");
|
||||
ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("dapr-job-1",
|
||||
JobSchedule.fromString("* * * * * *")).setData("Hello World!".getBytes());
|
||||
client.scheduleJob(scheduleJobRequest).block();
|
||||
|
||||
System.out.println("**** Scheduling job dapr-jobs-1 completed *****");
|
||||
|
||||
// Get a job.
|
||||
System.out.println("**** Retrieving a Job with name dapr-jobs-1 *****");
|
||||
GetJobResponse getJobResponse = client.getJob(new GetJobRequest("dapr-job-1")).block();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2021 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.jobs;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* Spring Boot application to demonstrate Dapr Jobs callback API.
|
||||
* <p>
|
||||
* This application demonstrates how to use Dapr Jobs API with Spring Boot.
|
||||
* </p>
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class DemoJobsSpringApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(DemoJobsSpringApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2021 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.jobs;
|
||||
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* SpringBoot Controller to handle jobs callback.
|
||||
*/
|
||||
@RestController
|
||||
public class JobsController {
|
||||
|
||||
/**
|
||||
* Handles jobs callback from Dapr.
|
||||
*
|
||||
* @param jobName name of the job.
|
||||
* @param payload data from the job if payload exists.
|
||||
* @return Empty Mono.
|
||||
*/
|
||||
@PostMapping("/job/{jobName}")
|
||||
public Mono<Void> handleJob(@PathVariable("jobName") String jobName,
|
||||
@RequestBody(required = false) byte[] payload) {
|
||||
System.out.println("Job Name: " + jobName);
|
||||
System.out.println("Job Payload: " + new String(payload));
|
||||
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
## Manage Dapr Jobs via the Jobs API
|
||||
|
||||
This example provides the different capabilities provided by Dapr Java SDK for Jobs. For further information about Job APIs please refer to [this link](https://docs.dapr.io/developing-applications/building-blocks/jobs/jobs-overview/)
|
||||
|
||||
### Using the Jobs API
|
||||
|
||||
The Java SDK exposes several methods for this -
|
||||
* `client.scheduleJob(...)` for scheduling a job.
|
||||
* `client.getJob(...)` for retrieving a scheduled job.
|
||||
* `client.deleteJob(...)` for deleting a job.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
* [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/).
|
||||
* Java JDK 11 (or greater):
|
||||
* [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11)
|
||||
* [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11)
|
||||
* [OpenJDK 11](https://jdk.java.net/11/)
|
||||
* [Apache Maven](https://maven.apache.org/install.html) version 3.x.
|
||||
|
||||
### Checking out the code
|
||||
|
||||
Clone this repository:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/dapr/java-sdk.git
|
||||
cd java-sdk
|
||||
```
|
||||
|
||||
Then build the Maven project:
|
||||
|
||||
```sh
|
||||
# make sure you are in the `java-sdk` directory.
|
||||
mvn install
|
||||
```
|
||||
|
||||
Then get into the examples directory:
|
||||
|
||||
```sh
|
||||
cd examples
|
||||
```
|
||||
|
||||
### Initialize Dapr
|
||||
|
||||
Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized.
|
||||
|
||||
### Running the example
|
||||
|
||||
This example uses the Java SDK Dapr client in order to **Schedule and Get** Jobs.
|
||||
`DemoJobsClient.java` is the example class demonstrating these features.
|
||||
Kindly check [DaprPreviewClient.java](https://github.com/dapr/java-sdk/blob/master/sdk/src/main/java/io/dapr/client/DaprPreviewClient.java) for a detailed description of the supported APIs.
|
||||
|
||||
```java
|
||||
public class DemoJobsClient {
|
||||
/**
|
||||
* The main method of this app to register and fetch jobs.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Map<Property<?>, String> overrides = Map.of(
|
||||
Properties.HTTP_PORT, "3500",
|
||||
Properties.GRPC_PORT, "51439"
|
||||
);
|
||||
|
||||
try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) {
|
||||
|
||||
// Schedule a job.
|
||||
ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("dapr-job-1",
|
||||
JobSchedule.fromString("* * * * * *")).setData("Hello World!".getBytes());
|
||||
client.scheduleJob(scheduleJobRequest).block();
|
||||
|
||||
// Get a job.
|
||||
GetJobResponse getJobResponse = client.getJob(new GetJobRequest("dapr-job-1")).block();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use the following command to run this example-
|
||||
|
||||
<!-- STEP
|
||||
name: Run Demo Jobs Client example
|
||||
expected_stdout_lines:
|
||||
- "== APP == Job Name: dapr-job-1"
|
||||
- "== APP == Job Payload: Hello World!"
|
||||
background: true
|
||||
output_match_mode: substring
|
||||
sleep: 10
|
||||
-->
|
||||
|
||||
```bash
|
||||
dapr run --resources-path ./components/configuration --app-id myapp --app-port 8080 --dapr-http-port 3500 --dapr-grpc-port 51439 --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsSpringApplication
|
||||
```
|
||||
|
||||
```bash
|
||||
java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsClient
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
||||
### Sample output
|
||||
```
|
||||
== APP == Job Name: dapr-job-1
|
||||
== APP == Job Payload: Hello World!
|
||||
```
|
||||
### Cleanup
|
||||
|
||||
To stop the app, run (or press CTRL+C):
|
||||
|
||||
<!-- STEP
|
||||
name: Cleanup
|
||||
-->
|
||||
|
||||
```bash
|
||||
dapr stop --app-id myapp
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
|
@ -19,8 +19,8 @@ import io.dapr.client.DaprPreviewClient;
|
|||
import io.dapr.client.domain.BulkPublishResponse;
|
||||
import io.dapr.client.domain.BulkPublishResponseFailedEntry;
|
||||
import io.dapr.examples.OpenTelemetryConfig;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
|
@ -55,28 +55,41 @@ public class BulkPublisher {
|
|||
* @throws Exception any exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
OpenTelemetry openTelemetry = OpenTelemetryConfig.createOpenTelemetry();
|
||||
Tracer tracer = openTelemetry.getTracer(BulkPublisher.class.getCanonicalName());
|
||||
Span span = tracer.spanBuilder("Bulk Publisher's Main").setSpanKind(Span.Kind.CLIENT).startSpan();
|
||||
OpenTelemetrySdk openTelemetrySdk = OpenTelemetryConfig.createOpenTelemetry();
|
||||
Tracer tracer = openTelemetrySdk.getTracer(BulkPublisher.class.getCanonicalName());
|
||||
Span span = tracer.spanBuilder("Bulk Publisher's Main").setSpanKind(SpanKind.CLIENT).startSpan();
|
||||
|
||||
try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient()) {
|
||||
DaprClient c = (DaprClient) client;
|
||||
|
||||
c.waitForSidecar(10000);
|
||||
|
||||
try (Scope scope = span.makeCurrent()) {
|
||||
System.out.println("Using preview client...");
|
||||
|
||||
List<String> messages = new ArrayList<>();
|
||||
|
||||
System.out.println("Constructing the list of messages to publish");
|
||||
|
||||
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||
String message = String.format("This is message #%d", i);
|
||||
|
||||
messages.add(message);
|
||||
|
||||
System.out.println("Going to publish message : " + message);
|
||||
}
|
||||
BulkPublishResponse<?> res = client.publishEvents(PUBSUB_NAME, TOPIC_NAME, "text/plain", messages)
|
||||
|
||||
BulkPublishResponse<?> res = client
|
||||
.publishEvents(PUBSUB_NAME, TOPIC_NAME, "text/plain", messages)
|
||||
.contextWrite(getReactorContext()).block();
|
||||
|
||||
System.out.println("Published the set of messages in a single call to Dapr");
|
||||
|
||||
if (res != null) {
|
||||
if (res.getFailedEntries().size() > 0) {
|
||||
// Ideally this condition will not happen in examples
|
||||
System.out.println("Some events failed to be published");
|
||||
|
||||
for (BulkPublishResponseFailedEntry<?> entry : res.getFailedEntries()) {
|
||||
System.out.println("EntryId : " + entry.getEntry().getEntryId()
|
||||
+ " Error message : " + entry.getErrorMessage());
|
||||
|
@ -86,16 +99,11 @@ public class BulkPublisher {
|
|||
throw new Exception("null response from dapr");
|
||||
}
|
||||
}
|
||||
// Close the span.
|
||||
|
||||
span.end();
|
||||
// Allow plenty of time for Dapr to export all relevant spans to the tracing infra.
|
||||
Thread.sleep(10000);
|
||||
// Shutdown the OpenTelemetry tracer.
|
||||
OpenTelemetrySdk.getGlobalTracerManagement().shutdown();
|
||||
|
||||
openTelemetrySdk.getSdkTracerProvider().shutdown();
|
||||
System.out.println("Done");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ package io.dapr.examples.pubsub;
|
|||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.examples.OpenTelemetryConfig;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
|
@ -51,19 +51,21 @@ public class PublisherWithTracing {
|
|||
* @throws Exception A startup Exception.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
OpenTelemetry openTelemetry = OpenTelemetryConfig.createOpenTelemetry();
|
||||
Tracer tracer = openTelemetry.getTracer(PublisherWithTracing.class.getCanonicalName());
|
||||
Span span = tracer.spanBuilder("Publisher's Main").setSpanKind(Span.Kind.CLIENT).startSpan();
|
||||
OpenTelemetrySdk openTelemetrySdk = OpenTelemetryConfig.createOpenTelemetry();
|
||||
Tracer tracer = openTelemetrySdk.getTracer(PublisherWithTracing.class.getCanonicalName());
|
||||
Span span = tracer.spanBuilder("Publisher's Main").setSpanKind(SpanKind.CLIENT).startSpan();
|
||||
|
||||
try (DaprClient client = new DaprClientBuilder().build()) {
|
||||
try (Scope scope = span.makeCurrent()) {
|
||||
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||
String message = String.format("This is message #%d", i);
|
||||
|
||||
// Publishing messages, notice the use of subscriberContext() for tracing.
|
||||
client.publishEvent(
|
||||
PUBSUB_NAME,
|
||||
TOPIC_NAME,
|
||||
message).contextWrite(getReactorContext()).block();
|
||||
|
||||
System.out.println("Published message: " + message);
|
||||
|
||||
try {
|
||||
|
@ -71,19 +73,14 @@ public class PublisherWithTracing {
|
|||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close the span.
|
||||
span.end();
|
||||
|
||||
// Shutdown the OpenTelemetry tracer.
|
||||
OpenTelemetrySdk.getGlobalTracerManagement().shutdown();
|
||||
|
||||
// This is an example, so for simplicity we are just exiting here.
|
||||
// Normally a dapr app would be a web service and not exit main.
|
||||
openTelemetrySdk.getSdkTracerProvider().shutdown();
|
||||
System.out.println("Done.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ import io.dapr.client.domain.HttpExtension;
|
|||
import io.dapr.client.domain.InvokeMethodRequest;
|
||||
import io.dapr.examples.OpenTelemetryConfig;
|
||||
import io.dapr.utils.TypeRef;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
|
@ -48,10 +48,10 @@ public class InvokeClient {
|
|||
* @param args Messages to be sent as request for the invoke API.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
final OpenTelemetry openTelemetry = OpenTelemetryConfig.createOpenTelemetry();
|
||||
final Tracer tracer = openTelemetry.getTracer(InvokeClient.class.getCanonicalName());
|
||||
OpenTelemetrySdk openTelemetrySdk = OpenTelemetryConfig.createOpenTelemetry();
|
||||
Tracer tracer = openTelemetrySdk.getTracer(InvokeClient.class.getCanonicalName());
|
||||
Span span = tracer.spanBuilder("Example's Main").setSpanKind(SpanKind.CLIENT).startSpan();
|
||||
|
||||
Span span = tracer.spanBuilder("Example's Main").setSpanKind(Span.Kind.CLIENT).startSpan();
|
||||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
for (String message : args) {
|
||||
try (Scope scope = span.makeCurrent()) {
|
||||
|
@ -70,15 +70,11 @@ public class InvokeClient {
|
|||
}).contextWrite(getReactorContext()).block();
|
||||
}
|
||||
}
|
||||
|
||||
span.end();
|
||||
openTelemetrySdk.getSdkTracerProvider().shutdown();
|
||||
Validation.validate();
|
||||
System.out.println("Done");
|
||||
}
|
||||
span.end();
|
||||
shutdown();
|
||||
System.out.println("Done");
|
||||
}
|
||||
|
||||
private static void shutdown() throws Exception {
|
||||
OpenTelemetrySdk.getGlobalTracerManagement().shutdown();
|
||||
Validation.validate();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@ import com.evanlennick.retry4j.config.RetryConfig;
|
|||
import com.evanlennick.retry4j.config.RetryConfigBuilder;
|
||||
import com.jayway.jsonpath.DocumentContext;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -34,7 +34,11 @@ import static java.time.temporal.ChronoUnit.SECONDS;
|
|||
*/
|
||||
final class Validation {
|
||||
|
||||
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient();
|
||||
private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
|
||||
.version(HttpClient.Version.HTTP_1_1)
|
||||
.build();
|
||||
|
||||
private static final String TRACES_URL = "http://localhost:9411/api/v2/traces";
|
||||
|
||||
private static final RetryConfig RETRY_CONFIG = new RetryConfigBuilder()
|
||||
.withMaxNumberOfTries(5)
|
||||
|
@ -56,27 +60,16 @@ final class Validation {
|
|||
|
||||
static void validate() {
|
||||
Status<Void> result = new CallExecutorBuilder().config(RETRY_CONFIG).build().execute(() -> doValidate());
|
||||
|
||||
if (!result.wasSuccessful()) {
|
||||
throw new RuntimeException(result.getLastExceptionThatCausedRetry());
|
||||
}
|
||||
}
|
||||
|
||||
private static Void doValidate() throws Exception {
|
||||
System.out.println("Performing validation of tracing events ...");
|
||||
|
||||
HttpUrl.Builder urlBuilder = new HttpUrl.Builder();
|
||||
urlBuilder.scheme("http")
|
||||
.host("localhost")
|
||||
.port(9411);
|
||||
urlBuilder.addPathSegments("api/v2/traces");
|
||||
Request.Builder requestBuilder = new Request.Builder()
|
||||
.url(urlBuilder.build());
|
||||
requestBuilder.method("GET", null);
|
||||
|
||||
Request request = requestBuilder.build();
|
||||
|
||||
Response response = HTTP_CLIENT.newCall(request).execute();
|
||||
DocumentContext documentContext = JsonPath.parse(response.body().string());
|
||||
HttpRequest request = HttpRequest.newBuilder().GET().uri(URI.create(TRACES_URL)).build();
|
||||
HttpResponse<String> response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
DocumentContext documentContext = JsonPath.parse(response.body());
|
||||
String mainSpanId = readOne(documentContext, "$..[?(@.name == \"example's main\")]['id']").toString();
|
||||
|
||||
// Validate echo
|
||||
|
@ -104,13 +97,14 @@ final class Validation {
|
|||
.toString();
|
||||
readOne(documentContext,
|
||||
String.format(JSONPATH_SLEEP_SPAN_ID, proxySleepSpanId2));
|
||||
System.out.println("Validation of tracing events has succeeded.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Object readOne(DocumentContext documentContext, String path) {
|
||||
List<Map<String, Object>> arr = documentContext.read(path);
|
||||
if (arr.size() == 0) {
|
||||
|
||||
if (arr.isEmpty()) {
|
||||
throw new RuntimeException("No record found for " + path);
|
||||
}
|
||||
|
||||
|
@ -119,6 +113,7 @@ final class Validation {
|
|||
|
||||
private static void assertCount(DocumentContext documentContext, String path, int expectedCount) {
|
||||
List<Map<String, Object>> arr = documentContext.read(path);
|
||||
|
||||
if (arr.size() != expectedCount) {
|
||||
throw new RuntimeException(
|
||||
String.format("Unexpected count %d vs expected %d for %s", arr.size(), expectedCount, path));
|
||||
|
|
|
@ -13,8 +13,8 @@ limitations under the License.
|
|||
|
||||
package io.dapr.examples.unittesting;
|
||||
|
||||
import com.microsoft.durabletask.Task;
|
||||
import com.microsoft.durabletask.TaskCanceledException;
|
||||
import io.dapr.durabletask.Task;
|
||||
import io.dapr.durabletask.TaskCanceledException;
|
||||
import io.dapr.workflows.Workflow;
|
||||
import io.dapr.workflows.WorkflowContext;
|
||||
import io.dapr.workflows.WorkflowStub;
|
||||
|
|
|
@ -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.
|
||||
|
@ -226,13 +227,13 @@ public class CountWordsActivity implements WorkflowActivity {
|
|||
@Override
|
||||
public Object run(WorkflowActivityContext ctx) {
|
||||
Logger logger = LoggerFactory.getLogger(ToUpperCaseActivity.class);
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
logger.info("Starting Activity: {}", ctx.getName());
|
||||
|
||||
String input = ctx.getInput(String.class);
|
||||
StringTokenizer tokenizer = new StringTokenizer(input);
|
||||
int result = tokenizer.countTokens();
|
||||
|
||||
logger.info("Activity returned: " + result);
|
||||
logger.info("Activity returned: {}.", result);
|
||||
logger.info("Activity finished");
|
||||
|
||||
return result;
|
||||
|
@ -244,10 +245,11 @@ name: Run Chaining Pattern workflow
|
|||
match_order: none
|
||||
output_match_mode: substring
|
||||
expected_stdout_lines:
|
||||
- 'Activity returned: 2'
|
||||
- 'Activity returned: 9'
|
||||
- 'Activity returned: 21'
|
||||
- 'Activity returned: 17'
|
||||
- 'Activity returned: 2.'
|
||||
- 'Activity returned: 9.'
|
||||
- 'Activity returned: 21.'
|
||||
- 'Activity returned: 17.'
|
||||
- 'Activity returned: 11.'
|
||||
- 'Workflow finished with result: 60'
|
||||
background: true
|
||||
sleep: 60
|
||||
|
@ -270,19 +272,19 @@ Now you can see the logs from worker:
|
|||
```text
|
||||
== APP == 2023-11-07 14:52:03,075 {HH:mm:ss.SSS} [main] INFO io.dapr.workflows.WorkflowContext - Starting Workflow: io.dapr.examples.workflows.faninout.DemoFanInOutWorkflow
|
||||
== APP == 2023-11-07 14:52:03,144 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Starting Activity: io.dapr.examples.workflows.faninout.CountWordsActivity
|
||||
== APP == 2023-11-07 14:52:03,147 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 2
|
||||
== APP == 2023-11-07 14:52:03,147 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 2.
|
||||
== APP == 2023-11-07 14:52:03,148 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity finished
|
||||
== APP == 2023-11-07 14:52:03,152 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Starting Activity: io.dapr.examples.workflows.faninout.CountWordsActivity
|
||||
== APP == 2023-11-07 14:52:03,152 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 9
|
||||
== APP == 2023-11-07 14:52:03,152 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 9.
|
||||
== APP == 2023-11-07 14:52:03,152 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity finished
|
||||
== APP == 2023-11-07 14:52:03,167 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Starting Activity: io.dapr.examples.workflows.faninout.CountWordsActivity
|
||||
== APP == 2023-11-07 14:52:03,167 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 21
|
||||
== APP == 2023-11-07 14:52:03,167 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 21.
|
||||
== APP == 2023-11-07 14:52:03,167 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity finished
|
||||
== APP == 2023-11-07 14:52:03,170 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Starting Activity: io.dapr.examples.workflows.faninout.CountWordsActivity
|
||||
== APP == 2023-11-07 14:52:03,170 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 17
|
||||
== APP == 2023-11-07 14:52:03,170 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 17.
|
||||
== APP == 2023-11-07 14:52:03,170 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity finished
|
||||
== APP == 2023-11-07 14:52:03,173 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Starting Activity: io.dapr.examples.workflows.faninout.CountWordsActivity
|
||||
== APP == 2023-11-07 14:52:03,173 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 11
|
||||
== APP == 2023-11-07 14:52:03,173 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity returned: 11.
|
||||
== APP == 2023-11-07 14:52:03,174 {HH:mm:ss.SSS} [main] INFO i.d.e.w.faninout.CountWordsActivity - Activity finished
|
||||
== APP == 2023-11-07 14:52:03,212 {HH:mm:ss.SSS} [main] INFO io.dapr.workflows.WorkflowContext - Workflow finished with result: 60
|
||||
```
|
||||
|
@ -352,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
|
||||
|
@ -418,7 +420,6 @@ client.raiseEvent(instanceId, "Approval", true);
|
|||
|
||||
Start the workflow and client using the following commands:
|
||||
|
||||
ex
|
||||
```sh
|
||||
dapr run --app-id demoworkflowworker --resources-path ./components/workflows -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.externalevent.DemoExternalEventWorker
|
||||
```
|
||||
|
@ -443,7 +444,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:
|
||||
|
@ -538,4 +539,172 @@ The log from client:
|
|||
```text
|
||||
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
|
||||
|
||||
|
||||
### Suspend/Resume Pattern
|
||||
|
||||
Workflow instances can be suspended and resumed. This example shows how to use the suspend and resume commands.
|
||||
|
||||
For testing the suspend and resume operations we will use the same workflow definition used by the DemoExternalEventWorkflow.
|
||||
|
||||
Start the workflow and client using the following commands:
|
||||
|
||||
|
||||
<!-- STEP
|
||||
name: Run Suspend/Resume workflow
|
||||
match_order: none
|
||||
output_match_mode: substring
|
||||
expected_stdout_lines:
|
||||
- "Waiting for approval..."
|
||||
- "Suspending Workflow Instance"
|
||||
- "Workflow Instance Status: SUSPENDED"
|
||||
- "Let's resume the Workflow Instance before sending the external event"
|
||||
- "Workflow Instance Status: RUNNING"
|
||||
- "Now that the instance is RUNNING again, lets send the external event."
|
||||
- "approval granted - do the approved action"
|
||||
- "Starting Activity: io.dapr.examples.workflows.externalevent.ApproveActivity"
|
||||
- "Running approval activity..."
|
||||
- "approval-activity finished"
|
||||
background: true
|
||||
sleep: 60
|
||||
timeout_seconds: 60
|
||||
-->
|
||||
|
||||
```sh
|
||||
dapr run --app-id demoworkflowworker --resources-path ./components/workflows --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeWorker
|
||||
```
|
||||
|
||||
```sh
|
||||
java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeClient
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
||||
The worker logs:
|
||||
```text
|
||||
== APP == 2023-11-07 16:01:23,279 {HH:mm:ss.SSS} [main] INFO io.dapr.workflows.WorkflowContext - Starting Workflow: io.dapr.examples.workflows.suspendresume.DemoExternalEventWorkflow
|
||||
== APP == 2023-11-07 16:01:23,279 {HH:mm:ss.SSS} [main] INFO io.dapr.workflows.WorkflowContext - Waiting for approval...
|
||||
== APP == 2023-11-07 16:01:23,324 {HH:mm:ss.SSS} [main] INFO io.dapr.workflows.WorkflowContext - approval granted - do the approved action
|
||||
== APP == 2023-11-07 16:01:23,348 {HH:mm:ss.SSS} [main] INFO i.d.e.w.e.ApproveActivity - Starting Activity: io.dapr.examples.workflows.externalevent.ApproveActivity
|
||||
== APP == 2023-11-07 16:01:23,348 {HH:mm:ss.SSS} [main] INFO i.d.e.w.e.ApproveActivity - Running approval activity...
|
||||
== APP == 2023-11-07 16:01:28,410 {HH:mm:ss.SSS} [main] INFO io.dapr.workflows.WorkflowContext - approval-activity finished
|
||||
```
|
||||
|
||||
The client log:
|
||||
```text
|
||||
Started a new external-event model workflow with instance ID: 23410d96-1afe-4698-9fcd-c01c1e0db255
|
||||
workflow instance with ID: 23410d96-1afe-4698-9fcd-c01c1e0db255 completed.
|
||||
```
|
|
@ -29,9 +29,8 @@ public class DemoChainWorker {
|
|||
builder.registerActivity(ToUpperCaseActivity.class);
|
||||
|
||||
// Build and then start the workflow runtime pulling and executing tasks
|
||||
try (WorkflowRuntime runtime = builder.build()) {
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
WorkflowRuntime runtime = builder.build();
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,13 @@ limitations under the License.
|
|||
|
||||
package io.dapr.examples.workflows.childworkflow;
|
||||
|
||||
import io.dapr.durabletask.interruption.OrchestratorBlockedException;
|
||||
import io.dapr.workflows.Workflow;
|
||||
import io.dapr.workflows.WorkflowStub;
|
||||
import io.dapr.workflows.WorkflowTaskOptions;
|
||||
import io.dapr.workflows.WorkflowTaskRetryPolicy;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class DemoChildWorkflow implements Workflow {
|
||||
@Override
|
||||
|
@ -22,11 +27,18 @@ public class DemoChildWorkflow implements Workflow {
|
|||
return ctx -> {
|
||||
ctx.getLogger().info("Starting ChildWorkflow: " + ctx.getName());
|
||||
|
||||
WorkflowTaskRetryPolicy policy = WorkflowTaskRetryPolicy.newBuilder()
|
||||
.setFirstRetryInterval(Duration.ofSeconds(1))
|
||||
.setMaxNumberOfAttempts(10)
|
||||
.build();
|
||||
|
||||
WorkflowTaskOptions options = new WorkflowTaskOptions(policy);
|
||||
|
||||
var childWorkflowInput = ctx.getInput(String.class);
|
||||
ctx.getLogger().info("ChildWorkflow received input: " + childWorkflowInput);
|
||||
|
||||
ctx.getLogger().info("ChildWorkflow is calling Activity: " + ReverseActivity.class.getName());
|
||||
String result = ctx.callActivity(ReverseActivity.class.getName(), childWorkflowInput, String.class).await();
|
||||
String result = ctx.callActivity(ReverseActivity.class.getName(), childWorkflowInput, options, String.class).await();
|
||||
|
||||
ctx.getLogger().info("ChildWorkflow finished with: " + result);
|
||||
ctx.complete(result);
|
||||
|
|
|
@ -31,9 +31,8 @@ public class DemoChildWorkflowWorker {
|
|||
builder.registerActivity(ReverseActivity.class);
|
||||
|
||||
// Build and then start the workflow runtime pulling and executing tasks
|
||||
try (WorkflowRuntime runtime = builder.build()) {
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
WorkflowRuntime runtime = builder.build();
|
||||
runtime.start();
|
||||
System.out.println("Start workflow runtime");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -16,6 +16,9 @@ package io.dapr.examples.workflows.continueasnew;
|
|||
import io.dapr.workflows.runtime.WorkflowRuntime;
|
||||
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class DemoContinueAsNewWorker {
|
||||
/**
|
||||
* The main method of this app.
|
||||
|
@ -25,13 +28,14 @@ public class DemoContinueAsNewWorker {
|
|||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Register the Workflow with the builder.
|
||||
WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder().registerWorkflow(DemoContinueAsNewWorkflow.class);
|
||||
WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder().
|
||||
registerWorkflow(DemoContinueAsNewWorkflow.class)
|
||||
.withExecutorService(Executors.newFixedThreadPool(3));
|
||||
builder.registerActivity(CleanUpActivity.class);
|
||||
|
||||
// Build and then start the workflow runtime pulling and executing tasks
|
||||
try (WorkflowRuntime runtime = builder.build()) {
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
WorkflowRuntime runtime = builder.build();
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,9 +30,8 @@ public class DemoExternalEventWorker {
|
|||
builder.registerActivity(DenyActivity.class);
|
||||
|
||||
// Build and then start the workflow runtime pulling and executing tasks
|
||||
try (WorkflowRuntime runtime = builder.build()) {
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
WorkflowRuntime runtime = builder.build();
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,13 +24,13 @@ public class CountWordsActivity implements WorkflowActivity {
|
|||
@Override
|
||||
public Object run(WorkflowActivityContext ctx) {
|
||||
Logger logger = LoggerFactory.getLogger(CountWordsActivity.class);
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
logger.info("Starting Activity: {}", ctx.getName());
|
||||
|
||||
String input = ctx.getInput(String.class);
|
||||
StringTokenizer tokenizer = new StringTokenizer(input);
|
||||
int result = tokenizer.countTokens();
|
||||
|
||||
logger.info("Activity returned: " + result);
|
||||
logger.info("Activity returned: {}.", result);
|
||||
logger.info("Activity finished");
|
||||
|
||||
return result;
|
||||
|
|
|
@ -29,9 +29,8 @@ public class DemoFanInOutWorker {
|
|||
builder.registerActivity(CountWordsActivity.class);
|
||||
|
||||
// Build and then start the workflow runtime pulling and executing tasks
|
||||
try (WorkflowRuntime runtime = builder.build()) {
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
WorkflowRuntime runtime = builder.build();
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ limitations under the License.
|
|||
|
||||
package io.dapr.examples.workflows.faninout;
|
||||
|
||||
import com.microsoft.durabletask.Task;
|
||||
import io.dapr.durabletask.Task;
|
||||
import io.dapr.workflows.Workflow;
|
||||
import io.dapr.workflows.WorkflowStub;
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.suspendresume;
|
||||
|
||||
import io.dapr.examples.workflows.externalevent.DemoExternalEventWorkflow;
|
||||
import io.dapr.workflows.client.DaprWorkflowClient;
|
||||
import io.dapr.workflows.client.WorkflowInstanceStatus;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class DemoSuspendResumeClient {
|
||||
/**
|
||||
* The main method to start the client.
|
||||
*
|
||||
* @param args Input arguments (unused).
|
||||
* @throws InterruptedException If program has been interrupted.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try (DaprWorkflowClient client = new DaprWorkflowClient()) {
|
||||
String instanceId = client.scheduleNewWorkflow(DemoExternalEventWorkflow.class);
|
||||
System.out.printf("Started a new external-event workflow with instance ID: %s%n", instanceId);
|
||||
|
||||
|
||||
System.out.printf("Suspending Workflow Instance: %s%n", instanceId );
|
||||
client.suspendWorkflow(instanceId, "suspending workflow instance.");
|
||||
|
||||
WorkflowInstanceStatus instanceState = client.getInstanceState(instanceId, false);
|
||||
assert instanceState != null;
|
||||
System.out.printf("Workflow Instance Status: %s%n", instanceState.getRuntimeStatus().name() );
|
||||
|
||||
System.out.printf("Let's resume the Workflow Instance before sending the external event: %s%n", instanceId );
|
||||
client.resumeWorkflow(instanceId, "resuming workflow instance.");
|
||||
|
||||
instanceState = client.getInstanceState(instanceId, false);
|
||||
assert instanceState != null;
|
||||
System.out.printf("Workflow Instance Status: %s%n", instanceState.getRuntimeStatus().name() );
|
||||
|
||||
System.out.printf("Now that the instance is RUNNING again, lets send the external event. %n");
|
||||
client.raiseEvent(instanceId, "Approval", true);
|
||||
|
||||
client.waitForInstanceCompletion(instanceId, null, true);
|
||||
System.out.printf("workflow instance with ID: %s completed.", instanceId);
|
||||
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.suspendresume;
|
||||
|
||||
import io.dapr.examples.workflows.externalevent.ApproveActivity;
|
||||
import io.dapr.examples.workflows.externalevent.DemoExternalEventWorkflow;
|
||||
import io.dapr.examples.workflows.externalevent.DenyActivity;
|
||||
import io.dapr.workflows.runtime.WorkflowRuntime;
|
||||
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
|
||||
|
||||
public class DemoSuspendResumeWorker {
|
||||
/**
|
||||
* The main method of this app.
|
||||
*
|
||||
* @param args The port the app will listen on.
|
||||
* @throws Exception An Exception.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Register the Workflow with the builder.
|
||||
WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder().registerWorkflow(DemoExternalEventWorkflow.class);
|
||||
builder.registerActivity(ApproveActivity.class);
|
||||
builder.registerActivity(DenyActivity.class);
|
||||
|
||||
// Build and then start the workflow runtime pulling and executing tasks
|
||||
WorkflowRuntime runtime = builder.build();
|
||||
System.out.println("Start workflow runtime");
|
||||
runtime.start();
|
||||
}
|
||||
}
|
378
pom.xml
378
pom.xml
|
@ -1,13 +1,13 @@
|
|||
<project
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
<name>dapr-sdk-parent</name>
|
||||
<description>SDK for Dapr.</description>
|
||||
<url>https://dapr.io</url>
|
||||
|
@ -17,15 +17,18 @@
|
|||
<grpc.version>1.69.0</grpc.version>
|
||||
<protobuf.version>3.25.5</protobuf.version>
|
||||
<protocCommand>protoc</protocCommand>
|
||||
<dapr.proto.baseurl>https://raw.githubusercontent.com/dapr/dapr/v1.14.4/dapr/proto</dapr.proto.baseurl>
|
||||
<dapr.sdk.version>1.14.2-rc-4</dapr.sdk.version>
|
||||
<dapr.sdk.alpha.version>0.14.2-rc-4</dapr.sdk.alpha.version>
|
||||
<dapr.proto.baseurl>https://raw.githubusercontent.com/dapr/dapr/v1.15.7/dapr/proto</dapr.proto.baseurl>
|
||||
<dapr.sdk.version>1.16.0-SNAPSHOT</dapr.sdk.version>
|
||||
<dapr.sdk.alpha.version>0.16.0-SNAPSHOT</dapr.sdk.alpha.version>
|
||||
<os-maven-plugin.version>1.7.1</os-maven-plugin.version>
|
||||
<maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version>
|
||||
<maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>
|
||||
<maven-deploy-plugin.version>2.7</maven-deploy-plugin.version>
|
||||
<maven-resources-plugin.version>3.3.1</maven-resources-plugin.version>
|
||||
<maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
|
||||
<maven-sources-plugin.version>3.2.1</maven-sources-plugin.version>
|
||||
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
|
||||
<jacoco-maven-plugin.coverage-ratio>80%</jacoco-maven-plugin.coverage-ratio>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
|
@ -33,7 +36,7 @@
|
|||
<!--
|
||||
manually declare durabletask-client's jackson dependencies for workflows sdk
|
||||
which conflict with dapr-sdk's jackson dependencies
|
||||
https://github.com/microsoft/durabletask-java/blob/main/client/build.gradle#L16
|
||||
https://github.com/dapr/durabletask-java/blob/main/client/build.gradle#L16
|
||||
-->
|
||||
<jackson.version>2.16.1</jackson.version>
|
||||
<gpg.skip>true</gpg.skip>
|
||||
|
@ -42,26 +45,42 @@
|
|||
<argLine>--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED</argLine>
|
||||
<failsafe.version>3.2.2</failsafe.version>
|
||||
<surefire.version>3.2.2</surefire.version>
|
||||
<junit-bom.version>5.8.2</junit-bom.version>
|
||||
<junit-bom.version>5.11.4</junit-bom.version>
|
||||
<snakeyaml.version>2.0</snakeyaml.version>
|
||||
<testcontainers.version>1.20.0</testcontainers.version>
|
||||
<springboot.version>3.4.3</springboot.version>
|
||||
<central-publishing-maven-plugin.version>0.8.0</central-publishing-maven-plugin.version>
|
||||
<testcontainers.version>1.21.3</testcontainers.version>
|
||||
<!-- Do NOT UPGRADE spring.version without checking springboot.version alignment -->
|
||||
<springboot.version>3.4.6</springboot.version>
|
||||
<springframework.version>6.2.7</springframework.version>
|
||||
<!-- Do NOT UPGRADE springframework.version without checking springboot.version alignment -->
|
||||
<nexus-staging-maven-plugin.version>1.7.0</nexus-staging-maven-plugin.version>
|
||||
<assertj.version>3.27.3</assertj.version>
|
||||
<grpc.version>1.69.0</grpc.version>
|
||||
<protobuf.version>3.25.5</protobuf.version>
|
||||
<opentelemetry.version>1.41.0</opentelemetry.version>
|
||||
<wiremock.version>3.9.1</wiremock.version>
|
||||
<jakarta.annotation.version>2.1.1</jakarta.annotation.version>
|
||||
<javax.annotation.version>1.3.2</javax.annotation.version>
|
||||
<commons-lang.version>3.18.0</commons-lang.version>
|
||||
<commons-cli.version>1.9.0</commons-cli.version>
|
||||
<commons-io.version>2.14.0</commons-io.version>
|
||||
<zipkin.version>3.4.0</zipkin.version>
|
||||
<microcks.version>0.3.1</microcks.version>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>central</id>
|
||||
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
|
||||
<id>ossrh</id>
|
||||
<url>https://ossrh-staging-api.central.sonatype.com/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<url>https://central.sonatype.com/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<site>
|
||||
<id>localDocsDirectory</id>
|
||||
<url>file:${maven.multiModuleProjectDirectory}/docs/</url>
|
||||
</site>
|
||||
<!-- Use default repository -->
|
||||
<!-- <repository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository> -->
|
||||
</distributionManagement>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -94,7 +113,6 @@
|
|||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.11.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
|
@ -114,17 +132,262 @@
|
|||
<version>${grpc.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit-bom.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit-bom.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit-bom.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>${junit-bom.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>kafka</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>rabbitmq</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<version>5.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-starter</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-starter-test</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-keyvalue</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<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>
|
||||
<version>${testcontainers.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mysql</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
<version>${jakarta.annotation.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<version>${javax.annotation.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>${commons-cli.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-protobuf</artifactId>
|
||||
<version>${grpc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-stub</artifactId>
|
||||
<version>${grpc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons-io.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-api</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-context</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk-common</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk-trace</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk-metrics</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-exporter-common</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-exporter-logging</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-exporter-zipkin</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/io.zipkin.reporter2/zipkin-reporter -->
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-reporter</artifactId>
|
||||
<version>${zipkin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-urlconnection</artifactId>
|
||||
<version>${zipkin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-actors</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-springboot</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>org.wiremock</groupId>
|
||||
<artifactId>wiremock-standalone</artifactId>
|
||||
<version>${wiremock.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>${maven-sources-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
|
@ -162,20 +425,67 @@
|
|||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>${maven-resources-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>${nexus-staging-maven-plugin.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<serverId>ossrh</serverId>
|
||||
<nexusUrl>https://ossrh-staging-api.central.sonatype.com</nexusUrl>
|
||||
<autoReleaseAfterClose>true</autoReleaseAfterClose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/jacoco-report/</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>check</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<rule>
|
||||
<element>BUNDLE</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>LINE</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco-maven-plugin.coverage-ratio}</minimum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.central</groupId>
|
||||
<artifactId>central-publishing-maven-plugin</artifactId>
|
||||
<version>${central-publishing-maven-plugin.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<publishingServerId>central</publishingServerId>
|
||||
<autoPublish>true</autoPublish>
|
||||
<waitUntil>published</waitUntil>
|
||||
</configuration>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
<parent>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-parent</artifactId>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-sdk-actors</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
<name>dapr-sdk-actors</name>
|
||||
<description>SDK for Actors on Dapr</description>
|
||||
|
||||
|
@ -31,12 +31,6 @@
|
|||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.gmazzo.okhttp.mock</groupId>
|
||||
<artifactId>mock-client</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
|
@ -45,7 +39,7 @@
|
|||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
<version>1.9.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -123,7 +123,6 @@ public class ActorId extends Object implements Comparable<ActorId> {
|
|||
return new ActorId(id.toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares if two actors have the same content.
|
||||
*
|
||||
|
|
|
@ -130,7 +130,6 @@ public class ActorClient implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build an instance of the Client based on the provided setup.
|
||||
*
|
||||
|
|
|
@ -42,7 +42,7 @@ class ActorProxyImpl implements ActorProxy, InvocationHandler {
|
|||
private final String actorType;
|
||||
|
||||
/**
|
||||
* Serializer/deserialzier to exchange message for Actors.
|
||||
* Serializer/deserializer to exchange message for Actors.
|
||||
*/
|
||||
private final DaprObjectSerializer serializer;
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
<parent>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-parent</artifactId>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-sdk-autogen</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
<name>dapr-sdk-autogen</name>
|
||||
<description>Auto-generated SDK for Dapr</description>
|
||||
|
||||
|
@ -55,11 +55,6 @@
|
|||
<version>${grpc.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okio</groupId>
|
||||
<artifactId>okio</artifactId>
|
||||
<version>3.9.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
<parent>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-parent</artifactId>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-sdk-springboot</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
<name>dapr-sdk-springboot</name>
|
||||
<description>SDK extension for Springboot</description>
|
||||
|
||||
|
@ -71,12 +71,6 @@
|
|||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.gmazzo.okhttp.mock</groupId>
|
||||
<artifactId>mock-client</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -13,7 +13,6 @@ limitations under the License.
|
|||
|
||||
package io.dapr.springboot;
|
||||
|
||||
|
||||
import io.dapr.actors.runtime.ActorRuntime;
|
||||
import io.dapr.serializer.DefaultObjectSerializer;
|
||||
import org.springframework.http.MediaType;
|
||||
|
@ -124,5 +123,4 @@ public class DaprController {
|
|||
@RequestBody(required = false) byte[] body) {
|
||||
return ActorRuntime.getInstance().invokeReminder(type, id, reminder, body);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -123,7 +123,6 @@ class DaprTopicSubscription {
|
|||
this(pubsubName, topic, route, "", routes, metadata, bulkSubscribe);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a subscription topic.
|
||||
*
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
|
||||
package io.dapr.springboot;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@RequestMapping(value = {"v1", "v2"})
|
||||
public class MockController {
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
<parent>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-parent</artifactId>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dapr-sdk-tests</artifactId>
|
||||
<version>1.14.2-rc-4</version>
|
||||
<version>1.16.0-SNAPSHOT</version>
|
||||
<name>dapr-sdk-tests</name>
|
||||
<description>Tests for Dapr's Java SDK - not to be published as a jar.</description>
|
||||
|
||||
|
@ -22,17 +22,15 @@
|
|||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<dapr.sdk.version>1.14.2-rc-4</dapr.sdk.version>
|
||||
<dapr.sdk.alpha.version>0.14.2-rc-4</dapr.sdk.alpha.version>
|
||||
<dapr.sdk.version>1.16.0-SNAPSHOT</dapr.sdk.version>
|
||||
<dapr.sdk.alpha.version>0.16.0-SNAPSHOT</dapr.sdk.alpha.version>
|
||||
<protobuf.output.directory>${project.build.directory}/generated-sources</protobuf.output.directory>
|
||||
<protobuf.input.directory>${project.basedir}/proto</protobuf.input.directory>
|
||||
<grpc.version>1.69.0</grpc.version>
|
||||
<protobuf.version>3.25.5</protobuf.version>
|
||||
<opentelemetry.version>1.41.0</opentelemetry.version>
|
||||
<springboot.version>3.4.3</springboot.version>
|
||||
<logback-core.version>1.5.16</logback-core.version>
|
||||
<wiremock.version>3.9.1</wiremock.version>
|
||||
<testcontainers-test.version>1.20.0</testcontainers-test.version>
|
||||
|
||||
<!-- The JaCoCo plugin was expecting coverage for this module, but since it's a test module
|
||||
and code coverage typically doesn't apply to tests, the coverage is set to 0. -->
|
||||
<jacoco-maven-plugin.coverage-ratio>0%</jacoco-maven-plugin.coverage-ratio>
|
||||
<junit-platform.version>1.11.4</junit-platform.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -45,119 +43,112 @@
|
|||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-commons</artifactId>
|
||||
<version>${junit-platform.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-engine</artifactId>
|
||||
<version>${junit-platform.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-protobuf</artifactId>
|
||||
<version>${grpc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-stub</artifactId>
|
||||
<version>${grpc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-api</artifactId>
|
||||
<version>${grpc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.14.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-api</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-context</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk-common</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk-trace</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-sdk-metrics</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-exporter-common</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-exporter-logging</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-exporter-zipkin</artifactId>
|
||||
<version>${opentelemetry.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/io.zipkin.reporter2/zipkin-reporter -->
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-reporter</artifactId>
|
||||
<version>3.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-okhttp3</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<artifactId>zipkin-sender-urlconnection</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-actors</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-springboot</artifactId>
|
||||
<version>${dapr.sdk.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr</groupId>
|
||||
<artifactId>dapr-sdk-workflows</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-starter</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dapr.spring</groupId>
|
||||
<artifactId>dapr-spring-boot-starter-test</artifactId>
|
||||
<version>${dapr.sdk.alpha.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -171,7 +162,6 @@
|
|||
<dependency>
|
||||
<groupId>org.wiremock</groupId>
|
||||
<artifactId>wiremock-standalone</artifactId>
|
||||
<version>${wiremock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -187,53 +177,95 @@
|
|||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback-core.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${testcontainers-test.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mysql</artifactId>
|
||||
<version>${testcontainers-test.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
<version>2.1.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.rekawek.toxiproxy</groupId>
|
||||
<artifactId>toxiproxy-java</artifactId>
|
||||
<version>2.1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-commons</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>toxiproxy</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/jacoco-report/</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>check</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<rule>
|
||||
<element>BUNDLE</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>LINE</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>${jacoco-maven-plugin.coverage-ratio}</minimum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.os72</groupId>
|
||||
<artifactId>protoc-jar-maven-plugin</artifactId>
|
||||
|
|
|
@ -24,17 +24,18 @@ import io.dapr.config.Property;
|
|||
import io.dapr.v1.AppCallbackHealthCheckGrpc;
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
@ -231,23 +232,21 @@ public class DaprRun implements Stoppable {
|
|||
channel.shutdown();
|
||||
}
|
||||
} else {
|
||||
// Create an OkHttpClient instance with a custom timeout
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.connectTimeout(maxWaitMilliseconds, TimeUnit.MILLISECONDS)
|
||||
.readTimeout(maxWaitMilliseconds, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
Duration waitDuration = Duration.ofMillis(maxWaitMilliseconds);
|
||||
HttpClient client = HttpClient.newBuilder()
|
||||
.version(HttpClient.Version.HTTP_1_1)
|
||||
.connectTimeout(waitDuration)
|
||||
.build();
|
||||
String url = "http://127.0.0.1:" + this.getAppPort() + "/health";
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.GET()
|
||||
.uri(URI.create(url))
|
||||
.build();
|
||||
|
||||
// Define the URL to probe
|
||||
String url = "http://127.0.0.1:" + this.getAppPort() + "/health"; // Change to your specific URL
|
||||
try {
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// Create a request to the URL
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
// Execute the request
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
if (!response.isSuccessful()) {
|
||||
if (response.statusCode() != 200) {
|
||||
throw new RuntimeException("error: HTTP service is not healthy.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
|
|
@ -55,7 +55,7 @@ public class ActorStateIT extends BaseIT {
|
|||
new ActorProxyBuilder(actorType, ActorProxy.class, deferClose(run.newActorClient()));
|
||||
ActorProxy proxy = proxyBuilder.build(actorId);
|
||||
|
||||
// wating for actor to be activated
|
||||
// waiting for actor to be activated
|
||||
Thread.sleep(5000);
|
||||
|
||||
// Validate conditional read works.
|
||||
|
|
|
@ -13,153 +13,204 @@ limitations under the License.
|
|||
|
||||
package io.dapr.it.resiliency;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
|
||||
import eu.rekawek.toxiproxy.Proxy;
|
||||
import eu.rekawek.toxiproxy.ToxiproxyClient;
|
||||
import eu.rekawek.toxiproxy.model.ToxicDirection;
|
||||
import eu.rekawek.toxiproxy.model.toxic.Latency;
|
||||
import eu.rekawek.toxiproxy.model.toxic.Timeout;
|
||||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.DaprClientImpl;
|
||||
import io.dapr.client.resiliency.ResiliencyOptions;
|
||||
import io.dapr.it.BaseIT;
|
||||
import io.dapr.it.DaprRun;
|
||||
import io.dapr.it.ToxiProxyRun;
|
||||
import io.dapr.config.Properties;
|
||||
import io.dapr.exceptions.DaprException;
|
||||
import io.dapr.testcontainers.DaprContainer;
|
||||
import io.dapr.testcontainers.DaprLogLevel;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Tags;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.containers.ToxiproxyContainer;
|
||||
import org.testcontainers.containers.output.Slf4jLogConsumer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.shaded.org.awaitility.Awaitility;
|
||||
import org.testcontainers.shaded.org.awaitility.core.ConditionTimeoutException;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.any;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.configureFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
|
||||
import static io.dapr.it.resiliency.SdkResiliencyIT.WIREMOCK_PORT;
|
||||
import static io.dapr.it.testcontainers.ContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||
import static io.dapr.it.testcontainers.ContainerConstants.TOXI_PROXY_IMAGE_TAG;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Test SDK resiliency.
|
||||
*/
|
||||
public class SdkResiliencyIT extends BaseIT {
|
||||
@Testcontainers
|
||||
@WireMockTest(httpPort = WIREMOCK_PORT)
|
||||
@Tags({@Tag("testcontainers"), @Tag("resiliency")})
|
||||
public class SdkResiliencyIT {
|
||||
|
||||
private static final int NUM_ITERATIONS = 35;
|
||||
public static final int WIREMOCK_PORT = 8888;
|
||||
private static final Network NETWORK = Network.newNetwork();
|
||||
private static final String STATE_STORE_NAME = "kvstore";
|
||||
private static final int INFINITE_RETRY = -1;
|
||||
|
||||
private static final Duration TIMEOUT = Duration.ofMillis(100);
|
||||
@Container
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
||||
.withAppName("dapr-app")
|
||||
.withAppPort(WIREMOCK_PORT)
|
||||
.withDaprLogLevel(DaprLogLevel.DEBUG)
|
||||
.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("dapr-logs")))
|
||||
.withAppHealthCheckPath("/actuator/health")
|
||||
.withAppChannelAddress("host.testcontainers.internal")
|
||||
.withNetworkAliases("dapr")
|
||||
.withNetwork(NETWORK);
|
||||
|
||||
private static final Duration LATENCY = TIMEOUT.dividedBy(3);
|
||||
@Container
|
||||
private static final ToxiproxyContainer TOXIPROXY = new ToxiproxyContainer(TOXI_PROXY_IMAGE_TAG)
|
||||
.withNetwork(NETWORK);
|
||||
|
||||
private static final Duration JITTER = TIMEOUT.multipliedBy(3);
|
||||
private static Proxy proxy;
|
||||
|
||||
private static final int MAX_RETRIES = -1; // Infinity
|
||||
private void configStub() {
|
||||
stubFor(any(urlMatching("/actuator/health"))
|
||||
.willReturn(aResponse().withBody("[]").withStatus(200)));
|
||||
|
||||
private static DaprClient daprClient;
|
||||
stubFor(any(urlMatching("/dapr/subscribe"))
|
||||
.willReturn(aResponse().withBody("[]").withStatus(200)));
|
||||
|
||||
private static ToxiProxyRun toxiProxyRun;
|
||||
stubFor(get(urlMatching("/dapr/config"))
|
||||
.willReturn(aResponse().withBody("[]").withStatus(200)));
|
||||
|
||||
private static DaprClient daprToxiClient;
|
||||
// create a stub for simulating dapr sidecar with timeout of 1000 ms
|
||||
stubFor(post(urlEqualTo("/dapr.proto.runtime.v1.Dapr/SaveState"))
|
||||
.willReturn(aResponse().withStatus(204).withFixedDelay(1000)));
|
||||
|
||||
private static DaprClient daprResilientClient;
|
||||
stubFor(any(urlMatching("/([a-z1-9]*)"))
|
||||
.willReturn(aResponse().withBody("[]").withStatus(200)));
|
||||
|
||||
private static DaprClient daprRetriesOnceClient;
|
||||
|
||||
private final String randomStateKeyPrefix = UUID.randomUUID().toString();
|
||||
configureFor("localhost", WIREMOCK_PORT);
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void init() throws Exception {
|
||||
DaprRun daprRun = startDaprApp(SdkResiliencyIT.class.getSimpleName(), 5000);
|
||||
daprClient = daprRun.newDaprClientBuilder().build();
|
||||
daprClient.waitForSidecar(8000).block();
|
||||
|
||||
toxiProxyRun = new ToxiProxyRun(daprRun, LATENCY, JITTER);
|
||||
toxiProxyRun.start();
|
||||
|
||||
daprToxiClient = toxiProxyRun.newDaprClientBuilder()
|
||||
.withResiliencyOptions(
|
||||
new ResiliencyOptions().setTimeout(TIMEOUT))
|
||||
.build();
|
||||
daprResilientClient = toxiProxyRun.newDaprClientBuilder()
|
||||
.withResiliencyOptions(
|
||||
new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(MAX_RETRIES))
|
||||
.build();
|
||||
daprRetriesOnceClient = toxiProxyRun.newDaprClientBuilder()
|
||||
.withResiliencyOptions(
|
||||
new ResiliencyOptions().setTimeout(TIMEOUT).setMaxRetries(1))
|
||||
.build();
|
||||
|
||||
assertTrue(daprClient instanceof DaprClientImpl);
|
||||
assertTrue(daprToxiClient instanceof DaprClientImpl);
|
||||
assertTrue(daprResilientClient instanceof DaprClientImpl);
|
||||
assertTrue(daprRetriesOnceClient instanceof DaprClientImpl);
|
||||
static void configure() throws IOException {
|
||||
ToxiproxyClient toxiproxyClient = new ToxiproxyClient(TOXIPROXY.getHost(), TOXIPROXY.getControlPort());
|
||||
proxy =
|
||||
toxiproxyClient.createProxy("dapr", "0.0.0.0:8666", "dapr:3500");
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() throws Exception {
|
||||
if (daprClient != null) {
|
||||
daprClient.close();
|
||||
}
|
||||
if (daprToxiClient != null) {
|
||||
daprToxiClient.close();
|
||||
}
|
||||
if (daprResilientClient != null) {
|
||||
daprResilientClient.close();
|
||||
}
|
||||
if (daprRetriesOnceClient != null) {
|
||||
daprRetriesOnceClient.close();
|
||||
}
|
||||
if (toxiProxyRun != null) {
|
||||
toxiProxyRun.stop();
|
||||
}
|
||||
static void afterAll() {
|
||||
WireMock.shutdownServer();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
configStub();
|
||||
org.testcontainers.Testcontainers.exposeHostPorts(WIREMOCK_PORT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retryAndTimeout() {
|
||||
AtomicInteger toxiClientErrorCount = new AtomicInteger();
|
||||
AtomicInteger retryOnceClientErrorCount = new AtomicInteger();
|
||||
|
||||
while (true){
|
||||
for (int i = 0; i < NUM_ITERATIONS; i++) {
|
||||
String key = randomStateKeyPrefix + "_" + i;
|
||||
String value = Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.UTF_8));
|
||||
try {
|
||||
daprToxiClient.saveState(STATE_STORE_NAME, key, value).block();
|
||||
} catch (Exception e) {
|
||||
// This call should fail sometimes. So, we count.
|
||||
toxiClientErrorCount.incrementAndGet();
|
||||
}
|
||||
try {
|
||||
daprRetriesOnceClient.saveState(STATE_STORE_NAME, key, value).block();
|
||||
} catch (Exception e) {
|
||||
// This call should fail sometimes. So, we count.
|
||||
retryOnceClientErrorCount.incrementAndGet();
|
||||
}
|
||||
|
||||
// We retry forever so that the call below should always work.
|
||||
daprResilientClient.saveState(STATE_STORE_NAME, key, value).block();
|
||||
// Makes sure the value was actually saved.
|
||||
String savedValue = daprClient.getState(STATE_STORE_NAME, key, String.class).block().getValue();
|
||||
assertEquals(value, savedValue);
|
||||
@DisplayName("should throw exception when the configured timeout exceeding waitForSidecar's timeout")
|
||||
public void testSidecarWithoutTimeout() {
|
||||
Assertions.assertThrows(RuntimeException.class, () -> {
|
||||
try (DaprClient client = createDaprClientBuilder().build()) {
|
||||
Timeout timeout = proxy.toxics().timeout("timeout", ToxicDirection.DOWNSTREAM, 3000);
|
||||
client.waitForSidecar(2000).block();
|
||||
timeout.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// We should have at least one success per client, otherwise retry.
|
||||
if(toxiClientErrorCount.get() < NUM_ITERATIONS && retryOnceClientErrorCount.get() < NUM_ITERATIONS){
|
||||
// This assertion makes sure that toxicity is on
|
||||
assertTrue(toxiClientErrorCount.get() > 0, "Toxi client error count is 0");
|
||||
assertTrue(retryOnceClientErrorCount.get() > 0, "Retry once client error count is 0");
|
||||
// A client without retries should have more errors than a client with one retry.
|
||||
@Test
|
||||
@DisplayName("should fail when resiliency options has 900ms and the latency is 950ms")
|
||||
public void shouldFailDueToLatencyExceedingConfiguration() throws Exception {
|
||||
Latency latency = proxy.toxics().latency("latency", ToxicDirection.DOWNSTREAM, Duration.ofMillis(950).toMillis());
|
||||
|
||||
String failureMessage = formatFailureMessage(toxiClientErrorCount, retryOnceClientErrorCount);
|
||||
assertTrue(toxiClientErrorCount.get() > retryOnceClientErrorCount.get(), failureMessage);
|
||||
break;
|
||||
}
|
||||
toxiClientErrorCount.set(0);
|
||||
retryOnceClientErrorCount.set(0);
|
||||
DaprClient client =
|
||||
createDaprClientBuilder().withResiliencyOptions(new ResiliencyOptions().setTimeout(Duration.ofMillis(900)))
|
||||
.build();
|
||||
|
||||
String errorMessage = assertThrows(DaprException.class, () -> {
|
||||
client.saveState(STATE_STORE_NAME, "users", "[]").block();
|
||||
}).getMessage();
|
||||
|
||||
assertThat(errorMessage).contains("DEADLINE_EXCEEDED");
|
||||
|
||||
latency.remove();
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail when resiliency's options has infinite retry with time 900ms and the latency is 950ms")
|
||||
public void shouldFailDueToLatencyExceedingConfigurationWithInfiniteRetry() throws Exception {
|
||||
Duration ms900 = Duration.ofMillis(900);
|
||||
Duration ms950 = Duration.ofMillis(950);
|
||||
|
||||
Latency latency = proxy.toxics().latency("latency-infinite-retry", ToxicDirection.DOWNSTREAM, ms950.toMillis());
|
||||
|
||||
DaprClient client =
|
||||
createDaprClientBuilder().withResiliencyOptions(new ResiliencyOptions().setTimeout(ms900).setMaxRetries(
|
||||
INFINITE_RETRY))
|
||||
.build();
|
||||
|
||||
Assertions.assertThrows(ConditionTimeoutException.class, () -> {
|
||||
Awaitility.await("10 seconds because the retry should be infinite")
|
||||
.atMost(Duration.ofSeconds(10))
|
||||
.until(() -> {
|
||||
boolean finished = true;
|
||||
client.saveState(STATE_STORE_NAME, "users", "[]").block();
|
||||
return finished;
|
||||
});
|
||||
});
|
||||
|
||||
latency.remove();
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail due to latency exceeding configuration with once retry")
|
||||
public void shouldFailDueToLatencyExceedingConfigurationWithOnceRetry() throws Exception {
|
||||
|
||||
DaprClient client =
|
||||
new DaprClientBuilder().withPropertyOverride(Properties.HTTP_ENDPOINT, "http://localhost:" + WIREMOCK_PORT)
|
||||
.withPropertyOverride(Properties.GRPC_ENDPOINT, "http://localhost:" + WIREMOCK_PORT)
|
||||
.withResiliencyOptions(new ResiliencyOptions().setTimeout(Duration.ofMillis(900))
|
||||
.setMaxRetries(1))
|
||||
.build();
|
||||
|
||||
try {
|
||||
client.saveState(STATE_STORE_NAME, "users", "[]").block();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
verify(2, postRequestedFor(urlEqualTo("/dapr.proto.runtime.v1.Dapr/SaveState")));
|
||||
|
||||
client.close();
|
||||
}
|
||||
|
||||
private static String formatFailureMessage(
|
||||
AtomicInteger toxiClientErrorCount,
|
||||
AtomicInteger retryOnceClientErrorCount
|
||||
) {
|
||||
return String.format(
|
||||
"Toxi client error count: %d, Retry once client error count: %d",
|
||||
toxiClientErrorCount.get(),
|
||||
retryOnceClientErrorCount.get()
|
||||
);
|
||||
private static DaprClientBuilder createDaprClientBuilder() {
|
||||
return new DaprClientBuilder()
|
||||
.withPropertyOverride(Properties.HTTP_ENDPOINT, "http://localhost:" + TOXIPROXY.getMappedPort(8666))
|
||||
.withPropertyOverride(Properties.GRPC_ENDPOINT, "http://localhost:" + TOXIPROXY.getMappedPort(8666));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,8 +35,10 @@ import java.util.Map;
|
|||
|
||||
import static io.dapr.it.spring.data.DaprSpringDataConstants.BINDING_NAME;
|
||||
import static io.dapr.it.spring.data.DaprSpringDataConstants.STATE_STORE_NAME;
|
||||
import static io.dapr.it.testcontainers.DaprContainerConstants.IMAGE_TAG;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static io.dapr.it.testcontainers.ContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link DaprKeyValueRepositoryIT}.
|
||||
|
@ -65,7 +67,7 @@ public class DaprKeyValueRepositoryIT {
|
|||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(IMAGE_TAG)
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
||||
.withAppName("postgresql-repository-dapr-app")
|
||||
.withNetwork(DAPR_NETWORK)
|
||||
.withComponent(new Component(STATE_STORE_NAME, "state.postgresql", "v1", STATE_STORE_PROPERTIES))
|
||||
|
|
|
@ -44,7 +44,7 @@ import java.util.Optional;
|
|||
|
||||
import static io.dapr.it.spring.data.DaprSpringDataConstants.STATE_STORE_NAME;
|
||||
import static io.dapr.it.spring.data.DaprSpringDataConstants.BINDING_NAME;
|
||||
import static io.dapr.it.testcontainers.DaprContainerConstants.IMAGE_TAG;
|
||||
import static io.dapr.it.testcontainers.ContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
@ -80,7 +80,7 @@ public class MySQLDaprKeyValueTemplateIT {
|
|||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(IMAGE_TAG)
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
||||
.withAppName("mysql-dapr-app")
|
||||
.withNetwork(DAPR_NETWORK)
|
||||
.withComponent(new Component(STATE_STORE_NAME, "state.mysql", "v1", STATE_STORE_PROPERTIES))
|
||||
|
|
|
@ -32,11 +32,15 @@ import org.testcontainers.containers.PostgreSQLContainer;
|
|||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static io.dapr.it.spring.data.DaprSpringDataConstants.BINDING_NAME;
|
||||
import static io.dapr.it.spring.data.DaprSpringDataConstants.STATE_STORE_NAME;
|
||||
import static io.dapr.it.testcontainers.DaprContainerConstants.IMAGE_TAG;
|
||||
import static io.dapr.it.testcontainers.ContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
@ -67,7 +71,7 @@ public class PostgreSQLDaprKeyValueTemplateIT {
|
|||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(IMAGE_TAG)
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
||||
.withAppName("postgresql-dapr-app")
|
||||
.withNetwork(DAPR_NETWORK)
|
||||
.withComponent(new Component(STATE_STORE_NAME, "state.postgresql", "v1", STATE_STORE_PROPERTIES))
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static io.dapr.it.testcontainers.DaprContainerConstants.IMAGE_TAG;
|
||||
import static io.dapr.it.testcontainers.ContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(
|
||||
|
@ -61,7 +61,7 @@ public class DaprSpringMessagingIT {
|
|||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(IMAGE_TAG)
|
||||
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
||||
.withAppName("messaging-dapr-app")
|
||||
.withNetwork(DAPR_NETWORK)
|
||||
.withComponent(new Component("pubsub", "pubsub.in-memory", "v1", Collections.emptyMap()))
|
||||
|
|
|
@ -331,7 +331,7 @@ public abstract class AbstractStateClientIT extends BaseIT {
|
|||
|
||||
|
||||
response = daprClient.getState(STATE_STORE_NAME, new State<>(stateKey, (MyData) null, null), MyData.class);
|
||||
//retrive the data wihout any etag
|
||||
//retrieve the data without any etag
|
||||
myDataResponse = response.block();
|
||||
|
||||
//review that state value changes
|
||||
|
@ -509,7 +509,7 @@ public abstract class AbstractStateClientIT extends BaseIT {
|
|||
public void saveUpdateAndGetStateWithEtagAndStateOptionsFirstWrite() {
|
||||
final String stateKey = "keyToBeUpdatedWithEtagAndOptions";
|
||||
|
||||
//create option with concurrency with first writte and consistency of strong
|
||||
//create option with concurrency with first write and consistency of strong
|
||||
StateOptions stateOptions = new StateOptions(StateOptions.Consistency.STRONG,
|
||||
StateOptions.Concurrency.FIRST_WRITE);
|
||||
|
||||
|
@ -571,7 +571,7 @@ public abstract class AbstractStateClientIT extends BaseIT {
|
|||
public void saveUpdateAndGetStateWithEtagAndStateOptionsLastWrite() {
|
||||
final String stateKey = "keyToBeUpdatedWithEtagAndOptions";
|
||||
|
||||
//create option with concurrency with first writte and consistency of strong
|
||||
//create option with concurrency with first write and consistency of strong
|
||||
StateOptions stateOptions = new StateOptions(StateOptions.Consistency.STRONG, StateOptions.Concurrency.LAST_WRITE);
|
||||
|
||||
//create dapr client
|
||||
|
@ -599,7 +599,7 @@ public abstract class AbstractStateClientIT extends BaseIT {
|
|||
assertEquals("data in property A", myDataResponse.getValue().getPropertyA());
|
||||
assertEquals("data in property B", myDataResponse.getValue().getPropertyB());
|
||||
|
||||
//change data to be udpated
|
||||
//change data to be updated
|
||||
data.setPropertyA("data in property A2");
|
||||
data.setPropertyB("data in property B2");
|
||||
//create deferred action to update the action with options
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package io.dapr.it.testcontainers;
|
||||
|
||||
import io.dapr.testcontainers.DaprContainerConstants;
|
||||
|
||||
public interface ContainerConstants {
|
||||
String DAPR_RUNTIME_IMAGE_TAG = DaprContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||
String DAPR_PLACEMENT_IMAGE_TAG = DaprContainerConstants.DAPR_PLACEMENT_IMAGE_TAG;
|
||||
String DAPR_SCHEDULER_IMAGE_TAG = DaprContainerConstants.DAPR_SCHEDULER_IMAGE_TAG;
|
||||
String TOXI_PROXY_IMAGE_TAG = "ghcr.io/shopify/toxiproxy:2.5.0";
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package io.dapr.it.testcontainers;
|
||||
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.config.Properties;
|
||||
import io.dapr.testcontainers.DaprContainer;
|
||||
|
||||
public interface DaprClientFactory {
|
||||
|
||||
static DaprClientBuilder createDaprClientBuilder(DaprContainer daprContainer) {
|
||||
return new DaprClientBuilder()
|
||||
.withPropertyOverride(Properties.HTTP_ENDPOINT, "http://localhost:" + daprContainer.getHttpPort())
|
||||
.withPropertyOverride(Properties.GRPC_ENDPOINT, "http://localhost:" + daprContainer.getGrpcPort());
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package io.dapr.it.testcontainers;
|
||||
|
||||
public interface DaprContainerConstants {
|
||||
String IMAGE_TAG = "daprio/daprd:1.14.1";
|
||||
}
|
|
@ -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.it.testcontainers;
|
||||
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.DaprPreviewClient;
|
||||
import io.dapr.config.Properties;
|
||||
import io.dapr.config.Property;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class DaprPreviewClientConfiguration {
|
||||
@Bean
|
||||
public DaprPreviewClient daprPreviewClient(
|
||||
@Value("${dapr.http.endpoint}") String daprHttpEndpoint,
|
||||
@Value("${dapr.grpc.endpoint}") String daprGrpcEndpoint
|
||||
){
|
||||
Map<Property<?>, String> overrides = Map.of(
|
||||
Properties.HTTP_ENDPOINT, daprHttpEndpoint,
|
||||
Properties.GRPC_ENDPOINT, daprGrpcEndpoint
|
||||
);
|
||||
|
||||
return new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue