diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b4901f45f..48ce0a97a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -112,18 +112,14 @@ jobs: wget -q ${{ env.TOXIPROXY_URL }} -O /home/runner/.local/bin/toxiproxy-server chmod +x /home/runner/.local/bin/toxiproxy-server /home/runner/.local/bin/toxiproxy-server --version - - name: Clean up files - run: ./mvnw clean -B - - name: Build sdk - run: ./mvnw compile -B -q + - name: Clean up and install sdk + run: ./mvnw clean install -B -q -DskipTests - name: Unit tests run: ./mvnw test # making it temporarily verbose. env: DOCKER_HOST: ${{steps.setup_docker.outputs.sock}} - name: Codecov uses: codecov/codecov-action@v5.5.0 - - 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 diff --git a/examples/src/main/java/io/dapr/examples/workflows/README.md b/examples/src/main/java/io/dapr/examples/workflows/README.md index 109e29ced..f867dbd4c 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/README.md +++ b/examples/src/main/java/io/dapr/examples/workflows/README.md @@ -147,7 +147,7 @@ background: true --> Execute the following script in order to run DemoChainWorker: ```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.chain.DemoChainWorker 50001 +dapr run --app-id chainingworker --resources-path ./components/workflows --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.chain.DemoChainWorker 50001 ``` Once running, the logs will start displaying the different steps: First, you can see workflow is starting: @@ -169,7 +169,8 @@ timeout_seconds: 20 --> Then, execute the following script in order to run DemoChainClient: ```sh -sleep 10 && java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.chain.DemoChainClient 50001 +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.chain.DemoChainClient 50001 +dapr stop --app-id chainingworker ``` @@ -266,7 +267,7 @@ background: true Execute the following script in order to run DemoFanInOutWorker: ```sh -dapr run --app-id demoworkflowworker --resources-path ./components/workflows --dapr-grpc-port 50002 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.faninout.DemoFanInOutWorker 50002 +dapr run --app-id faninoutworker --resources-path ./components/workflows --dapr-grpc-port 50002 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.faninout.DemoFanInOutWorker 50002 ``` @@ -282,7 +283,8 @@ timeout_seconds: 20 Execute the following script in order to run DemoFanInOutClient: ```sh -sleep 10 && java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.faninout.DemoFanInOutClient 50002 +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.faninout.DemoFanInOutClient 50002 +dapr stop --app-id faninoutworker ``` @@ -660,7 +662,8 @@ timeout_seconds: 30 --> Once running, execute the following script to run the BookTripClient: ```sh -sleep 15 && java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.compensation.BookTripClient 50003 +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.compensation.BookTripClient 50003 +dapr stop --app-id book-trip-worker ``` @@ -702,7 +705,7 @@ timeout_seconds: 30 --> ```sh -dapr run --app-id demoworkflowworker --resources-path ./components/workflows --dapr-grpc-port 50004 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeWorker 50004 +dapr run --app-id suspendresumeworker --resources-path ./components/workflows --dapr-grpc-port 50004 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeWorker 50004 ``` @@ -720,7 +723,8 @@ expected_stdout_lines: timeout_seconds: 30 --> ```sh -sleep 15 && java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeClient 50004 +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeClient 50004 +dapr stop --app-id suspendresumeworker ``` diff --git a/examples/src/main/java/io/dapr/examples/workflows/chain/DemoChainClient.java b/examples/src/main/java/io/dapr/examples/workflows/chain/DemoChainClient.java index 6c9eedbdc..334e40f8d 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/chain/DemoChainClient.java +++ b/examples/src/main/java/io/dapr/examples/workflows/chain/DemoChainClient.java @@ -14,9 +14,11 @@ limitations under the License. package io.dapr.examples.workflows.chain; import io.dapr.examples.workflows.utils.PropertyUtils; +import io.dapr.examples.workflows.utils.RetryUtils; import io.dapr.workflows.client.DaprWorkflowClient; import io.dapr.workflows.client.WorkflowInstanceStatus; +import java.time.Duration; import java.util.concurrent.TimeoutException; public class DemoChainClient { @@ -28,15 +30,15 @@ public class DemoChainClient { */ public static void main(String[] args) { try (DaprWorkflowClient client = new DaprWorkflowClient(PropertyUtils.getProperties(args))) { - String instanceId = client.scheduleNewWorkflow(DemoChainWorkflow.class); + String instanceId = RetryUtils.callWithRetry(() -> client.scheduleNewWorkflow(DemoChainWorkflow.class), + Duration.ofSeconds(60)); + System.out.printf("Started a new chaining model workflow with instance ID: %s%n", instanceId); WorkflowInstanceStatus workflowInstanceStatus = client.waitForInstanceCompletion(instanceId, null, true); String result = workflowInstanceStatus.readOutputAs(String.class); System.out.printf("workflow instance with ID: %s completed with result: %s%n", instanceId, result); - - } catch (TimeoutException | InterruptedException e) { throw new RuntimeException(e); } diff --git a/examples/src/main/java/io/dapr/examples/workflows/compensation/BookTripClient.java b/examples/src/main/java/io/dapr/examples/workflows/compensation/BookTripClient.java index ce76d5de1..b7c4760e5 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/compensation/BookTripClient.java +++ b/examples/src/main/java/io/dapr/examples/workflows/compensation/BookTripClient.java @@ -14,6 +14,7 @@ limitations under the License. package io.dapr.examples.workflows.compensation; import io.dapr.examples.workflows.utils.PropertyUtils; +import io.dapr.examples.workflows.utils.RetryUtils; import io.dapr.workflows.client.DaprWorkflowClient; import io.dapr.workflows.client.WorkflowInstanceStatus; @@ -23,7 +24,7 @@ import java.util.concurrent.TimeoutException; public class BookTripClient { public static void main(String[] args) { try (DaprWorkflowClient client = new DaprWorkflowClient(PropertyUtils.getProperties(args))) { - String instanceId = client.scheduleNewWorkflow(BookTripWorkflow.class); + String instanceId = RetryUtils.callWithRetry(() -> client.scheduleNewWorkflow(BookTripWorkflow.class), Duration.ofSeconds(60)); System.out.printf("Started a new trip booking workflow with instance ID: %s%n", instanceId); WorkflowInstanceStatus status = client.waitForInstanceCompletion(instanceId, Duration.ofMinutes(30), true); diff --git a/examples/src/main/java/io/dapr/examples/workflows/faninout/DemoFanInOutClient.java b/examples/src/main/java/io/dapr/examples/workflows/faninout/DemoFanInOutClient.java index 612a8979d..871b15cfe 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/faninout/DemoFanInOutClient.java +++ b/examples/src/main/java/io/dapr/examples/workflows/faninout/DemoFanInOutClient.java @@ -14,6 +14,7 @@ limitations under the License. package io.dapr.examples.workflows.faninout; import io.dapr.examples.workflows.utils.PropertyUtils; +import io.dapr.examples.workflows.utils.RetryUtils; import io.dapr.workflows.client.DaprWorkflowClient; import io.dapr.workflows.client.WorkflowInstanceStatus; @@ -40,9 +41,10 @@ public class DemoFanInOutClient { "Always remember that you are absolutely unique. Just like everyone else."); // Schedule an orchestration which will reliably count the number of words in all the given sentences. - String instanceId = client.scheduleNewWorkflow( + String instanceId = RetryUtils.callWithRetry(() -> client.scheduleNewWorkflow( DemoFanInOutWorkflow.class, - listOfStrings); + listOfStrings), Duration.ofSeconds(60)); + System.out.printf("Started a new fan out/fan in model workflow with instance ID: %s%n", instanceId); // Block until the orchestration completes. Then print the final status, which includes the output. diff --git a/examples/src/main/java/io/dapr/examples/workflows/suspendresume/DemoSuspendResumeClient.java b/examples/src/main/java/io/dapr/examples/workflows/suspendresume/DemoSuspendResumeClient.java index 5880c64f2..5b94b5fa5 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/suspendresume/DemoSuspendResumeClient.java +++ b/examples/src/main/java/io/dapr/examples/workflows/suspendresume/DemoSuspendResumeClient.java @@ -15,9 +15,11 @@ package io.dapr.examples.workflows.suspendresume; import io.dapr.examples.workflows.externalevent.DemoExternalEventWorkflow; import io.dapr.examples.workflows.utils.PropertyUtils; +import io.dapr.examples.workflows.utils.RetryUtils; import io.dapr.workflows.client.DaprWorkflowClient; import io.dapr.workflows.client.WorkflowInstanceStatus; +import java.time.Duration; import java.util.concurrent.TimeoutException; public class DemoSuspendResumeClient { @@ -29,7 +31,7 @@ public class DemoSuspendResumeClient { */ public static void main(String[] args) { try (DaprWorkflowClient client = new DaprWorkflowClient(PropertyUtils.getProperties(args))) { - String instanceId = client.scheduleNewWorkflow(DemoExternalEventWorkflow.class); + String instanceId = RetryUtils.callWithRetry(() -> client.scheduleNewWorkflow(DemoExternalEventWorkflow.class), Duration.ofSeconds(60)); System.out.printf("Started a new external-event workflow with instance ID: %s%n", instanceId); diff --git a/examples/src/main/java/io/dapr/examples/workflows/utils/RetryUtils.java b/examples/src/main/java/io/dapr/examples/workflows/utils/RetryUtils.java new file mode 100644 index 000000000..42651b06b --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/workflows/utils/RetryUtils.java @@ -0,0 +1,47 @@ +/* + * 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.utils; + +import java.time.Duration; +import java.util.concurrent.Callable; + +public class RetryUtils { + private static final long RETRY_WAIT_MILLISECONDS = 1000; + + public static String callWithRetry(Callable function, Duration retryTimeout) throws InterruptedException { + var retryTimeoutMilliseconds = retryTimeout.toMillis(); + long started = System.currentTimeMillis(); + while (true) { + Throwable exception; + try { + return function.call(); + } catch (Exception | AssertionError e) { + exception = e; + } + + long elapsed = System.currentTimeMillis() - started; + if (elapsed >= retryTimeoutMilliseconds) { + if (exception instanceof RuntimeException) { + throw (RuntimeException) exception; + } + + throw new RuntimeException(exception); + } + + long remaining = retryTimeoutMilliseconds - elapsed; + Thread.sleep(Math.min(remaining, RETRY_WAIT_MILLISECONDS)); + } + } + +} diff --git a/pom.xml b/pom.xml index 6ea7d1e51..9f7b17028 100644 --- a/pom.xml +++ b/pom.xml @@ -658,6 +658,18 @@ sdk-tests + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + diff --git a/sdk-tests/pom.xml b/sdk-tests/pom.xml index 7a0fca81d..a9d2e1358 100644 --- a/sdk-tests/pom.xml +++ b/sdk-tests/pom.xml @@ -315,18 +315,6 @@ org.apache.maven.plugins maven-failsafe-plugin 3.2.2 - - - - integration-test - verify - - - - ${skipITs} - - - diff --git a/spring-boot-examples/workflows/README.md b/spring-boot-examples/workflows/README.md index 595857cb1..d62eded71 100644 --- a/spring-boot-examples/workflows/README.md +++ b/spring-boot-examples/workflows/README.md @@ -65,7 +65,6 @@ match_order: none output_match_mode: substring expected_stdout_lines: - 'TOKYO, LONDON, SEATTLE' -background: true timeout_seconds: 90 --> @@ -73,7 +72,7 @@ timeout_seconds: 90 To start the workflow with the three chained activities you can run: ```sh -sleep 35 && curl -X POST localhost:8080/wfp/chain -H 'Content-Type: application/json' +curl -X POST localhost:8080/wfp/chain -H 'Content-Type: application/json' --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ``` @@ -142,7 +141,6 @@ match_order: none output_match_mode: substring expected_stdout_lines: - '!wolfkroW rpaD olleH' -background: true timeout_seconds: 90 --> @@ -150,7 +148,7 @@ timeout_seconds: 90 To start the workflow with the three chained activities you can run: ```sh -sleep 35 && curl -X POST localhost:8080/wfp/child -H 'Content-Type: application/json' +curl -X POST localhost:8080/wfp/child -H 'Content-Type: application/json' --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ``` @@ -191,13 +189,12 @@ match_order: none output_match_mode: substring expected_stdout_lines: - '{"cleanUpTimes":5}' -background: true timeout_seconds: 90 --> ```sh -sleep 30 && curl -X POST localhost:8080/wfp/continueasnew -H 'Content-Type: application/json' +curl -X POST localhost:8080/wfp/continueasnew -H 'Content-Type: application/json' --retry 10 --max-time 60 --retry-all-errors --retry-max-time 90 ``` @@ -260,13 +257,12 @@ To start the workflow you can run: name: Start External Event Workflow match_order: none output_match_mode: substring -background: true timeout_seconds: 90 --> ```sh -sleep 30 && curl -X POST "localhost:8080/wfp/externalevent?orderId=123" -H 'Content-Type: application/json' +curl -X POST "localhost:8080/wfp/externalevent?orderId=123" -H 'Content-Type: application/json' --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ``` @@ -290,7 +286,6 @@ match_order: none output_match_mode: substring expected_stdout_lines: - '{"approved":true}' -background: true timeout_seconds: 90 --> @@ -298,7 +293,7 @@ timeout_seconds: 90 To send the event you can run: ```sh -sleep 42 && curl -X POST "localhost:8080/wfp/externalevent-continue?orderId=123&decision=true" -H 'Content-Type: application/json' +curl -X POST "localhost:8080/wfp/externalevent-continue?orderId=123&decision=true" -H 'Content-Type: application/json' --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ``` @@ -346,13 +341,12 @@ match_order: none output_match_mode: substring expected_stdout_lines: - '{"wordCount":60}' -background: true timeout_seconds: 90 --> ```sh -sleep 45 && curl -X POST localhost:8080/wfp/fanoutin -H 'Content-Type: application/json' -d @body.json +curl -X POST localhost:8080/wfp/fanoutin -H 'Content-Type: application/json' -d @body.json --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ``` @@ -398,13 +392,12 @@ To start the workflow, you can run: name: Start Suspend/Resume Workflow match_order: none output_match_mode: substring -background: true timeout_seconds: 90 --> ```sh -sleep 50 && curl -X POST "localhost:8080/wfp/suspendresume?orderId=456" -H 'Content-Type: application/json' +curl -X POST "localhost:8080/wfp/suspendresume?orderId=456" -H 'Content-Type: application/json' --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ``` @@ -431,7 +424,6 @@ match_order: none output_match_mode: substring expected_stdout_lines: - 'SUSPENDED' -background: true timeout_seconds: 90 --> @@ -439,7 +431,7 @@ timeout_seconds: 90 Let's suspend the workflow instance by sending the following request: ```sh -sleep 55 && curl -X POST "localhost:8080/wfp/suspendresume/suspend?orderId=456" -H 'Content-Type: application/json' +curl -X POST "localhost:8080/wfp/suspendresume/suspend?orderId=456" -H 'Content-Type: application/json' --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ``` @@ -459,7 +451,6 @@ match_order: none output_match_mode: substring expected_stdout_lines: - 'RUNNING' -background: true timeout_seconds: 90 --> @@ -467,7 +458,7 @@ timeout_seconds: 90 To send the event you can run: ```sh -sleep 60 && curl -X POST "localhost:8080/wfp/suspendresume/resume?orderId=456" -H 'Content-Type: application/json' +curl -X POST "localhost:8080/wfp/suspendresume/resume?orderId=456" -H 'Content-Type: application/json' --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ``` @@ -487,7 +478,6 @@ match_order: none output_match_mode: substring expected_stdout_lines: - '{"approved":true}' -background: true timeout_seconds: 90 --> @@ -495,7 +485,7 @@ timeout_seconds: 90 To send the event you can run: ```sh -sleep 65 && curl -X POST "localhost:8080/wfp/suspendresume/continue?orderId=456&decision=true" -H 'Content-Type: application/json' +curl -X POST "localhost:8080/wfp/suspendresume/continue?orderId=456&decision=true" -H 'Content-Type: application/json' --retry 10 --max-time 20 --retry-all-errors --retry-max-time 90 ```