diff --git a/.github/workflows/parallel-examples-probe.yml b/.github/workflows/parallel-examples-probe.yml new file mode 100644 index 0000000000..dfb38dc10b --- /dev/null +++ b/.github/workflows/parallel-examples-probe.yml @@ -0,0 +1,64 @@ +# TEMPORARY probe — validates the full 17-README parallel run on one shared dapr +# runtime and self-reports failures as annotations. Removed once green; not for master. +name: Parallel Examples Probe + +on: + workflow_dispatch: + push: + branches: + - users/svegiraju/parallel-examples-probe + +jobs: + probe: + runs-on: ubuntu-latest + timeout-minutes: 40 + env: + JDK_VER: 17 + DAPR_CLI_VER: 1.18.0 + DAPR_RUNTIME_VER: 1.18.0 + DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/v1.18.0/install/install.sh + steps: + - uses: actions/checkout@v7 + - name: Set up OpenJDK ${{ env.JDK_VER }} + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: ${{ env.JDK_VER }} + - 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: Uninstall any existing Dapr + run: dapr uninstall --all || true + - name: Initialize Dapr runtime ${{ env.DAPR_RUNTIME_VER }} + run: dapr init --runtime-version ${{ env.DAPR_RUNTIME_VER }} + - name: Verify scheduler is listening + run: sleep 20 && docker logs dapr_scheduler && nc -vz localhost 50006 + - name: Install mechanical-markdown + run: | + echo "PATH=$PATH:$HOME/.local/bin" >> $GITHUB_ENV + pip3 install setuptools wheel + pip3 install mechanical-markdown + - name: Build SDK + examples jar + run: ./mvnw -pl examples -am clean install -B -q -DskipTests + - name: Static parallel-safety check (all 17 READMEs) + run: bash examples/validate/check-parallel-safe.sh + - name: Sequential baseline (-j 1, all 17) + run: | + echo "::group::sequential" + time bash examples/validate/run-parallel.sh -j 1 + echo "::endgroup::" + - name: Parallel run on one shared runtime (-j 2, all 17) + run: | + set +e + echo "::group::parallel" + time bash examples/validate/run-parallel.sh -j 2 2>&1 | tee /tmp/par.out + rc=${PIPESTATUS[0]} + echo "::endgroup::" + if [ "$rc" -ne 0 ]; then + echo "---- parallel failures (as annotations) ----" + grep -nE "^ FAIL |Caused by|ALREADY_EXISTS|signal: killed|error code|Exception|is not found|DAPR_|Reason:" /tmp/par.out | head -40 | while IFS= read -r line; do + echo "::error::$line" + done + fi + exit "$rc" diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 74290000a2..67093352b5 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -121,22 +121,8 @@ jobs: retry_wait_seconds: 10 command: | set -e - (cd examples && mm.py ./src/main/java/io/dapr/examples/crypto/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/workflows/README.md) + # Example READMEs run concurrently against one shared Dapr runtime via the + # parallel-safe runner examples/validate/run-parallel.sh. + bash examples/validate/run-parallel.sh -j 2 (cd spring-boot-examples && mm.py README.md) (cd spring-boot-examples/workflows/patterns && mm.py README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/jobs/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/conversation/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/invoke/http/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/invoke/grpc/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/tracing/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/exception/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/state/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/pubsub/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/bindings/http/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/secrets/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/unittesting/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/configuration/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/actors/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/querystate/README.md) - (cd examples && mm.py ./src/main/java/io/dapr/examples/pubsub/stream/README.md) diff --git a/examples/components/pubsub/redis_messagebus.yaml b/examples/components/pubsub/redis_messagebus.yaml index 40dbdf558b..4e6fe6cd68 100644 --- a/examples/components/pubsub/redis_messagebus.yaml +++ b/examples/components/pubsub/redis_messagebus.yaml @@ -10,8 +10,14 @@ spec: value: localhost:6379 - name: redisPassword value: "" +# NOTE: this pubsub component is scoped to specific app-ids. When an example's +# app-id is renamed for parallel-safe validation, the matching scope entry MUST +# be renamed too, or Dapr reports "pubsub messagebus is not found" for that app. +# Shared by the pubsub and pubsub/stream examples — keep both examples' app-ids here. scopes: - - publisher - - bulk-publisher - - subscriber - - publisher-tracing \ No newline at end of file + - pubsub-publisher + - pubsub-bulk-publisher + - pubsub-subscriber + - pubsub-publisher-tracing + - pubsub-stream-subscriber + - pubsub-stream-publisher \ No newline at end of file diff --git a/examples/src/main/java/io/dapr/examples/actors/README.md b/examples/src/main/java/io/dapr/examples/actors/README.md index d19ca99251..2c7befc15a 100644 --- a/examples/src/main/java/io/dapr/examples/actors/README.md +++ b/examples/src/main/java/io/dapr/examples/actors/README.md @@ -171,7 +171,7 @@ timeout_seconds: 90 Now, execute the following script in order to run DemoActorService: ```sh -dapr run --resources-path ./components/actors --app-id demoactorservice --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.actors.DemoActorService -p 3000 +dapr run --resources-path ./components/actors --app-id actors-demoactorservice --app-port 3100 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.actors.DemoActorService -p 3100 ``` ### Running the Actor client @@ -252,7 +252,7 @@ timeout_seconds: 45 ```sh -dapr run --resources-path ./components/actors --app-id demoactorclient -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.actors.DemoActorClient +dapr run --resources-path ./components/actors --app-id actors-demoactorclient -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.actors.DemoActorClient ``` diff --git a/examples/src/main/java/io/dapr/examples/bindings/http/README.md b/examples/src/main/java/io/dapr/examples/bindings/http/README.md index cdb356623f..f1e35976b7 100644 --- a/examples/src/main/java/io/dapr/examples/bindings/http/README.md +++ b/examples/src/main/java/io/dapr/examples/bindings/http/README.md @@ -139,7 +139,7 @@ sleep: 10 --> ```bash -dapr run --resources-path ./components/bindings --app-id inputbinding --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.bindings.http.InputBindingExample -p 3000 +dapr run --resources-path ./components/bindings --app-id bindings-http-inputbinding --app-port 3120 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.bindings.http.InputBindingExample -p 3120 ``` @@ -209,7 +209,7 @@ sleep: 30 --> ```bash -dapr run --resources-path ./components/bindings --app-id outputbinding -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.bindings.http.OutputBindingExample +dapr run --resources-path ./components/bindings --app-id bindings-http-outputbinding -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.bindings.http.OutputBindingExample ``` @@ -249,8 +249,8 @@ name: Cleanup apps --> ```bash -dapr stop --app-id inputbinding -dapr stop --app-id outputbinding +dapr stop --app-id bindings-http-inputbinding +dapr stop --app-id bindings-http-outputbinding ``` diff --git a/examples/src/main/java/io/dapr/examples/configuration/README.md b/examples/src/main/java/io/dapr/examples/configuration/README.md index 6b95603bad..7315f1fe0b 100644 --- a/examples/src/main/java/io/dapr/examples/configuration/README.md +++ b/examples/src/main/java/io/dapr/examples/configuration/README.md @@ -158,7 +158,7 @@ sleep: 10 --> ```bash -dapr run --resources-path ./components/configuration --app-id configgrpc --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.ConfigurationClient +dapr run --resources-path ./components/configuration --app-id configuration-configgrpc --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.configuration.ConfigurationClient ``` @@ -185,7 +185,7 @@ name: Cleanup --> ```bash -dapr stop --app-id configgrpc +dapr stop --app-id configuration-configgrpc ``` diff --git a/examples/src/main/java/io/dapr/examples/conversation/README.md b/examples/src/main/java/io/dapr/examples/conversation/README.md index a9fb7f8d54..0e5c91b580 100644 --- a/examples/src/main/java/io/dapr/examples/conversation/README.md +++ b/examples/src/main/java/io/dapr/examples/conversation/README.md @@ -109,7 +109,7 @@ 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.UserMessageDemo +dapr run --resources-path ./components/conversation --app-id conversation-myapp --app-port 3160 --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.conversation.UserMessageDemo ``` @@ -128,7 +128,7 @@ name: Cleanup --> ```bash -dapr stop --app-id myapp +dapr stop --app-id conversation-myapp ``` diff --git a/examples/src/main/java/io/dapr/examples/crypto/CryptoExample.java b/examples/src/main/java/io/dapr/examples/crypto/CryptoExample.java index 977ac76c30..edd167e04b 100644 --- a/examples/src/main/java/io/dapr/examples/crypto/CryptoExample.java +++ b/examples/src/main/java/io/dapr/examples/crypto/CryptoExample.java @@ -66,8 +66,8 @@ public static void main(String[] args) throws Exception { generateKeysIfNeeded(); Map, String> overrides = Map.of( - Properties.HTTP_PORT, "3500", - Properties.GRPC_PORT, "50001" + Properties.HTTP_PORT, "3180", + Properties.GRPC_PORT, "3181" ); try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) { diff --git a/examples/src/main/java/io/dapr/examples/crypto/README.md b/examples/src/main/java/io/dapr/examples/crypto/README.md index f0e5538e0d..c6b6aa9c14 100644 --- a/examples/src/main/java/io/dapr/examples/crypto/README.md +++ b/examples/src/main/java/io/dapr/examples/crypto/README.md @@ -117,7 +117,7 @@ sleep: 30 --> ```bash -dapr run --resources-path ./components/crypto --app-id crypto-app --dapr-http-port 3500 --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.crypto.CryptoExample +dapr run --resources-path ./components/crypto --app-id crypto-app --dapr-http-port 3180 --dapr-grpc-port 3181 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.crypto.CryptoExample ``` @@ -130,7 +130,7 @@ dapr run --resources-path ./components/crypto --app-id crypto-app --dapr-http-po - Custom encryption ciphers ```bash -dapr run --resources-path ./components/crypto --app-id crypto-app --dapr-http-port 3500 --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.crypto.StreamingCryptoExample +dapr run --resources-path ./components/crypto --app-id crypto-app --dapr-http-port 3180 --dapr-grpc-port 3181 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.crypto.StreamingCryptoExample ``` ### Sample Output diff --git a/examples/src/main/java/io/dapr/examples/crypto/StreamingCryptoExample.java b/examples/src/main/java/io/dapr/examples/crypto/StreamingCryptoExample.java index 038cf8ad9b..94aead0ab7 100644 --- a/examples/src/main/java/io/dapr/examples/crypto/StreamingCryptoExample.java +++ b/examples/src/main/java/io/dapr/examples/crypto/StreamingCryptoExample.java @@ -61,8 +61,8 @@ public static void main(String[] args) throws Exception { generateKeysIfNeeded(); Map, String> overrides = Map.of( - Properties.HTTP_PORT, "3500", - Properties.GRPC_PORT, "50001" + Properties.HTTP_PORT, "3180", + Properties.GRPC_PORT, "3181" ); try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) { diff --git a/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldClient.java b/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldClient.java index 8105a06641..5db0b2dc05 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldClient.java +++ b/examples/src/main/java/io/dapr/examples/invoke/grpc/HelloWorldClient.java @@ -44,7 +44,7 @@ public static void main(String[] args) throws Exception { String user = "World"; try (DaprClient client = new DaprClientBuilder().build()) { HelloWorldGrpc.HelloWorldBlockingStub blockingStub = client.newGrpcStub( - "hellogrpc", + "invoke-grpc-hellogrpc", channel -> HelloWorldGrpc.newBlockingStub(channel)); logger.info("Will try to greet " + user + " ..."); diff --git a/examples/src/main/java/io/dapr/examples/invoke/grpc/README.md b/examples/src/main/java/io/dapr/examples/invoke/grpc/README.md index 0772711f05..4552766965 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/grpc/README.md +++ b/examples/src/main/java/io/dapr/examples/invoke/grpc/README.md @@ -84,7 +84,7 @@ sleep: 1 --> ```bash -dapr run --app-id hellogrpc --app-port 5000 --app-protocol grpc -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.grpc.HelloWorldService -p 5000 +dapr run --app-id invoke-grpc-hellogrpc --app-port 3220 --app-protocol grpc -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.grpc.HelloWorldService -p 3220 ``` @@ -131,7 +131,7 @@ sleep: 10 --> ```bash -dapr run --app-id invokegrpc --app-protocol grpc -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.grpc.HelloWorldClient +dapr run --app-id invoke-grpc-invokegrpc --app-protocol grpc -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.grpc.HelloWorldClient ``` @@ -145,8 +145,8 @@ name: Cleanup --> ```bash -dapr stop --app-id hellogrpc -dapr stop --app-id invokegrpc +dapr stop --app-id invoke-grpc-hellogrpc +dapr stop --app-id invoke-grpc-invokegrpc ``` diff --git a/examples/src/main/java/io/dapr/examples/invoke/http/InvokeClient.java b/examples/src/main/java/io/dapr/examples/invoke/http/InvokeClient.java index b97d24312c..22197578a0 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/http/InvokeClient.java +++ b/examples/src/main/java/io/dapr/examples/invoke/http/InvokeClient.java @@ -46,7 +46,7 @@ public class InvokeClient { /** * Identifier in Dapr for the service this client will invoke. */ - private static final String SERVICE_APP_ID = "invokedemo"; + private static final String SERVICE_APP_ID = "invoke-http-invokedemo"; /** * Method on the target service to invoke. diff --git a/examples/src/main/java/io/dapr/examples/invoke/http/README.md b/examples/src/main/java/io/dapr/examples/invoke/http/README.md index e86241a10c..c7495a669e 100644 --- a/examples/src/main/java/io/dapr/examples/invoke/http/README.md +++ b/examples/src/main/java/io/dapr/examples/invoke/http/README.md @@ -125,7 +125,7 @@ sleep: 5 --> ```sh -dapr run --app-id invokedemo --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.http.DemoService -p 3000 +dapr run --app-id invoke-http-invokedemo --app-port 3240 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.http.DemoService -p 3240 ``` @@ -145,7 +145,7 @@ In `InvokeClient.java` file, you will find the `InvokeClient` class and the `mai ```java public class InvokeClient { - private static final String SERVICE_APP_ID = "invokedemo"; + private static final String SERVICE_APP_ID = "invoke-http-invokedemo"; private static final String METHOD = "say"; public static void main(String[] args) throws Exception { @@ -197,7 +197,7 @@ sleep: 5 --> ```sh -dapr run --app-id invokeclient -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.http.InvokeClient "message one" "message two" +dapr run --app-id invoke-http-invokeclient -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.http.InvokeClient "message one" "message two" ``` @@ -223,8 +223,8 @@ name: Cleanup --> ```bash -dapr stop --app-id invokedemo -dapr stop --app-id invokeclient +dapr stop --app-id invoke-http-invokedemo +dapr stop --app-id invoke-http-invokeclient ``` diff --git a/examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java b/examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java index ddc8ac78e0..f86ff2c4cf 100644 --- a/examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java +++ b/examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java @@ -16,6 +16,7 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.DaprPreviewClient; +import io.dapr.client.domain.DeleteJobRequest; import io.dapr.client.domain.GetJobRequest; import io.dapr.client.domain.GetJobResponse; import io.dapr.client.domain.JobSchedule; @@ -32,12 +33,20 @@ public class DemoJobsClient { */ public static void main(String[] args) throws Exception { Map, String> overrides = Map.of( - Properties.HTTP_PORT, "3500", - Properties.GRPC_PORT, "51439" + Properties.HTTP_PORT, "3261", + Properties.GRPC_PORT, "3262" ); try (DaprClient client = new DaprClientBuilder().withPropertyOverrides(overrides).build()) { + // The scheduler persists this recurring job across runs, so delete any + // pre-existing instance first to keep the example idempotent / re-runnable. + try { + client.deleteJob(new DeleteJobRequest("dapr-job-1")).block(); + } catch (Exception e) { + System.out.println("No existing 'dapr-job-1' to delete (first run): " + e.getMessage()); + } + // Schedule a job. System.out.println("**** Scheduling a Job with name dapr-jobs-1 *****"); ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("dapr-job-1", diff --git a/examples/src/main/java/io/dapr/examples/jobs/README.md b/examples/src/main/java/io/dapr/examples/jobs/README.md index 35a788ed32..889c1f5e24 100644 --- a/examples/src/main/java/io/dapr/examples/jobs/README.md +++ b/examples/src/main/java/io/dapr/examples/jobs/README.md @@ -104,7 +104,7 @@ 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 +dapr run --resources-path ./components/configuration --app-id jobs-myapp --app-port 3260 --dapr-http-port 3261 --dapr-grpc-port 3262 --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsSpringApplication --server.port=3260 ``` ```bash @@ -127,7 +127,7 @@ name: Cleanup --> ```bash -dapr stop --app-id myapp +dapr stop --app-id jobs-myapp ``` diff --git a/examples/src/main/java/io/dapr/examples/pubsub/README.md b/examples/src/main/java/io/dapr/examples/pubsub/README.md index 873231e661..014718a06d 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/README.md +++ b/examples/src/main/java/io/dapr/examples/pubsub/README.md @@ -202,7 +202,7 @@ sleep: 15 --> ```bash -dapr run --resources-path ./components/pubsub --app-id publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher +dapr run --resources-path ./components/pubsub --app-id pubsub-publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher ``` @@ -402,7 +402,7 @@ background: true --> ```bash -dapr run --resources-path ./components/pubsub --app-id bulk-publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.BulkPublisher +dapr run --resources-path ./components/pubsub --app-id pubsub-bulk-publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.BulkPublisher ``` @@ -471,7 +471,7 @@ background: true --> ```bash -dapr run --resources-path ./components/pubsub --app-id publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher testingtopicbulk +dapr run --resources-path ./components/pubsub --app-id pubsub-publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher testingtopicbulk ``` @@ -600,7 +600,7 @@ sleep: 15 --> ```bash -dapr run --resources-path ./components/pubsub --app-id subscriber --app-port 3000 --app-protocol http -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.http.Subscriber -p 3000 +dapr run --resources-path ./components/pubsub --app-id pubsub-subscriber --app-port 3280 --app-protocol http -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.http.Subscriber -p 3280 ``` @@ -717,11 +717,11 @@ sleep: 15 --> ```bash # stop http subscriber if you have started one. -dapr stop --app-id subscriber +dapr stop --app-id pubsub-subscriber # start a grpc subscriber -dapr run --resources-path ./components/pubsub --app-id subscriber --app-port 3000 --app-protocol grpc -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.grpc.Subscriber -p 3000 +dapr run --resources-path ./components/pubsub --app-id pubsub-subscriber --app-port 3280 --app-protocol grpc -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.grpc.Subscriber -p 3280 ``` @@ -737,7 +737,7 @@ sleep: 15 --> ```bash -dapr run --resources-path ./components/pubsub --app-id publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher +dapr run --resources-path ./components/pubsub --app-id pubsub-publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher ``` @@ -768,7 +768,7 @@ background: true --> ```bash -dapr run --resources-path ./components/pubsub --app-id publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher testingtopicbulk +dapr run --resources-path ./components/pubsub --app-id pubsub-publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher testingtopicbulk ``` @@ -837,7 +837,7 @@ sleep: 15 --> ```bash -dapr run --resources-path ./components/pubsub --app-id publisher-tracing -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.PublisherWithTracing +dapr run --resources-path ./components/pubsub --app-id pubsub-publisher-tracing -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.PublisherWithTracing ``` @@ -866,12 +866,12 @@ mvn install Run the publisher app: ```sh -dapr run --resources-path ./components/pubsub --app-id publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher +dapr run --resources-path ./components/pubsub --app-id pubsub-publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher ``` Wait until all 10 messages are published like before, then wait for a few more seconds and run the subscriber app: ```sh -dapr run --resources-path ./components/pubsub --app-id subscriber --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Subscriber -p 3000 +dapr run --resources-path ./components/pubsub --app-id pubsub-subscriber --app-port 3280 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Subscriber -p 3280 ``` No message is consumed by the subscriber app and warnings messages are emitted from Dapr sidecar: @@ -907,14 +907,14 @@ name: Cleanup --> Use the following command to stop your running http subscriber or gRPC subscriber. ```bash -dapr stop --app-id subscriber +dapr stop --app-id pubsub-subscriber ``` After completing publish , the application will automatically exit. However, you can still use the following command to stop your running publisher. ```bash -dapr stop --app-id publisher -dapr stop --app-id bulk-publisher +dapr stop --app-id pubsub-publisher +dapr stop --app-id pubsub-bulk-publisher ``` diff --git a/examples/src/main/java/io/dapr/examples/pubsub/stream/README.md b/examples/src/main/java/io/dapr/examples/pubsub/stream/README.md index 969138738e..96627dcff3 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/stream/README.md +++ b/examples/src/main/java/io/dapr/examples/pubsub/stream/README.md @@ -159,7 +159,7 @@ timeout_seconds: 30 --> ```bash -dapr run --resources-path ./components/pubsub --app-id subscriber -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.stream.Subscriber +dapr run --resources-path ./components/pubsub --app-id pubsub-stream-subscriber -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.stream.Subscriber ``` @@ -167,14 +167,14 @@ dapr run --resources-path ./components/pubsub --app-id subscriber -- java -jar t Or run the CloudEvent Subscriber example: ```bash -dapr run --resources-path ./components/pubsub --app-id subscriber -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.stream.SubscriberCloudEvent +dapr run --resources-path ./components/pubsub --app-id pubsub-stream-subscriber -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.stream.SubscriberCloudEvent ``` Or run the dead-letter Subscriber example, which routes messages whose payload contains "fail" to a dead-letter topic and consumes both topics: ```bash -dapr run --resources-path ./components/pubsub --app-id subscriber -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.stream.SubscriberWithDeadLetter +dapr run --resources-path ./components/pubsub --app-id pubsub-stream-subscriber -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.stream.SubscriberWithDeadLetter ``` Once the subscriber is running, run the publisher in a new terminal to see the events in the subscriber's side: @@ -190,7 +190,7 @@ timeout_seconds: 30 --> ```bash -dapr run --resources-path ./components/pubsub --app-id publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher +dapr run --resources-path ./components/pubsub --app-id pubsub-stream-publisher -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.pubsub.Publisher pubsub-stream-testingtopic ``` diff --git a/examples/src/main/java/io/dapr/examples/pubsub/stream/Subscriber.java b/examples/src/main/java/io/dapr/examples/pubsub/stream/Subscriber.java index e9456dc24c..eb841d8c15 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/stream/Subscriber.java +++ b/examples/src/main/java/io/dapr/examples/pubsub/stream/Subscriber.java @@ -33,7 +33,7 @@ */ public class Subscriber { - private static final String DEFAULT_TOPIC_NAME = "testingtopic"; + private static final String DEFAULT_TOPIC_NAME = "pubsub-stream-testingtopic"; private static final String PUBSUB_NAME = "messagebus"; /** diff --git a/examples/src/main/java/io/dapr/examples/pubsub/stream/SubscriberCloudEvent.java b/examples/src/main/java/io/dapr/examples/pubsub/stream/SubscriberCloudEvent.java index 5f52d51d04..8c44f8fe7d 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/stream/SubscriberCloudEvent.java +++ b/examples/src/main/java/io/dapr/examples/pubsub/stream/SubscriberCloudEvent.java @@ -36,7 +36,7 @@ */ public class SubscriberCloudEvent { - private static final String DEFAULT_TOPIC_NAME = "testingtopic"; + private static final String DEFAULT_TOPIC_NAME = "pubsub-stream-testingtopic"; private static final String PUBSUB_NAME = "messagebus"; /** diff --git a/examples/src/main/java/io/dapr/examples/pubsub/stream/SubscriberWithDeadLetter.java b/examples/src/main/java/io/dapr/examples/pubsub/stream/SubscriberWithDeadLetter.java index 8fcf91bdb2..8c5074f280 100644 --- a/examples/src/main/java/io/dapr/examples/pubsub/stream/SubscriberWithDeadLetter.java +++ b/examples/src/main/java/io/dapr/examples/pubsub/stream/SubscriberWithDeadLetter.java @@ -42,8 +42,8 @@ */ public class SubscriberWithDeadLetter { - private static final String DEFAULT_TOPIC_NAME = "testingtopic"; - private static final String DEFAULT_DEAD_LETTER_TOPIC_NAME = "testingtopic-deadletter"; + private static final String DEFAULT_TOPIC_NAME = "pubsub-stream-testingtopic"; + private static final String DEFAULT_DEAD_LETTER_TOPIC_NAME = "pubsub-stream-testingtopic-deadletter"; private static final String PUBSUB_NAME = "messagebus"; /** diff --git a/examples/src/main/java/io/dapr/examples/querystate/README.md b/examples/src/main/java/io/dapr/examples/querystate/README.md index 8d1a12298b..db253e8991 100644 --- a/examples/src/main/java/io/dapr/examples/querystate/README.md +++ b/examples/src/main/java/io/dapr/examples/querystate/README.md @@ -260,7 +260,7 @@ sleep: 10 Run this example with the following command: ```bash -dapr run --resources-path ./components/state --app-id query-state-example -H 3600 -- java -Ddapr.api.protocol=HTTP -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.querystate.QuerySavedState +dapr run --resources-path ./components/state --app-id querystate-query-state-example -- java -Ddapr.api.protocol=HTTP -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.querystate.QuerySavedState ``` @@ -294,7 +294,7 @@ name: Cleanup --> ```bash -dapr stop --app-id query-state-example +dapr stop --app-id querystate-query-state-example ``` diff --git a/examples/src/main/java/io/dapr/examples/secrets/README.md b/examples/src/main/java/io/dapr/examples/secrets/README.md index aed39d63eb..cd111f2b05 100644 --- a/examples/src/main/java/io/dapr/examples/secrets/README.md +++ b/examples/src/main/java/io/dapr/examples/secrets/README.md @@ -123,7 +123,7 @@ sleep: 5 --> ```bash -dapr run --resources-path ./components/secrets --app-id secrets1 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.secrets.SecretClient localSecretStore redisPassword randomKey +dapr run --resources-path ./components/secrets --app-id secrets-secrets1 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.secrets.SecretClient localSecretStore redisPassword randomKey ``` @@ -142,7 +142,7 @@ name: Cleanup first app --> ```bash -dapr stop --app-id secrets1 +dapr stop --app-id secrets-secrets1 ``` @@ -176,7 +176,7 @@ sleep: 5 --> ```sh -dapr run --resources-path ./components/secrets --config ./src/main/java/io/dapr/examples/secrets/config.yaml --app-id secrets2 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.secrets.SecretClient localSecretStore redisPassword randomKey +dapr run --resources-path ./components/secrets --config ./src/main/java/io/dapr/examples/secrets/config.yaml --app-id secrets-secrets2 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.secrets.SecretClient localSecretStore redisPassword randomKey ``` @@ -195,7 +195,7 @@ name: Cleanup second app --> ```bash -dapr stop --app-id secrets2 +dapr stop --app-id secrets-secrets2 ``` diff --git a/examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java b/examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java index 5bbd7b4bc9..55f5745c3c 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java +++ b/examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java @@ -42,7 +42,7 @@ public class InvokeClient { /** * Identifier in Dapr for the service this client will invoke. */ - private static final String SERVICE_APP_ID = "tracingdemoproxy"; + private static final String SERVICE_APP_ID = "tracing-tracingdemoproxy"; /** * Starts the invoke client. diff --git a/examples/src/main/java/io/dapr/examples/tracing/README.md b/examples/src/main/java/io/dapr/examples/tracing/README.md index 4f7945ec5b..06e1e2b726 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/README.md +++ b/examples/src/main/java/io/dapr/examples/tracing/README.md @@ -142,7 +142,7 @@ timeout_seconds: 40 --> ```bash -dapr run --app-id tracingdemo --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3000 +dapr run --app-id tracing-tracingdemo --app-port 3380 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3380 ``` @@ -230,7 +230,7 @@ timeout_seconds: 40 --> ```bash -dapr run --app-id tracingdemoproxy --app-port 3001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3001 +dapr run --app-id tracing-tracingdemoproxy --app-port 3381 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3381 ``` @@ -242,7 +242,7 @@ This sample code uses the Dapr SDK for invoking two remote methods (`proxy_echo` ```java public class InvokeClient { -private static final String SERVICE_APP_ID = "tracingdemoproxy"; +private static final String SERVICE_APP_ID = "tracing-tracingdemoproxy"; ///... public static void main(String[] args) throws Exception { final OpenTelemetry openTelemetry = OpenTelemetryConfig.createOpenTelemetry(); @@ -290,12 +290,12 @@ timeout_seconds: 40 --> ```bash -dapr run --app-id tracingdemoclient -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.InvokeClient "message one" "message two" +dapr run --app-id tracing-tracingdemoclient -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.InvokeClient "message one" "message two" ``` -Open the `tracingdemo` console and check the output as follows: +Open the `tracing-tracingdemo` console and check the output as follows: ```txt Server: "\"message one\"" @ 2021-03-10 22:10:23.598 and metadata: {"user-agent":"okhttp/4.9.0","host":"127.0.0.1:3000","content-type":"application/json; charset=utf-8","content-length":"17","connection":"Keep-Alive","x-daprrequestid":"00d801df-2773-4b9d-b389-12d0a93d6b90","accept-encoding":"gzip","x-forwarded-for":"192.168.1.15","x-forwarded-host":"X","forwarded":"for=192.168.1.15;by=192.168.1.15;host=X","traceparent":"00-4659182fd55c552b84fa291e3157d215-d0145c33df26c04d-01"} diff --git a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoMiddleServiceController.java b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoMiddleServiceController.java index 134deda33c..871b1c86c6 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoMiddleServiceController.java +++ b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoMiddleServiceController.java @@ -37,7 +37,7 @@ @RestController public class TracingDemoMiddleServiceController { - private static final String INVOKE_APP_ID = "tracingdemo"; + private static final String INVOKE_APP_ID = "tracing-tracingdemo"; private static final HttpClient httpClient = HttpClient.newHttpClient(); diff --git a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoService.java b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoService.java index 60f0726d9d..4f5502d144 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/TracingDemoService.java +++ b/examples/src/main/java/io/dapr/examples/tracing/TracingDemoService.java @@ -29,11 +29,11 @@ * mvn clean install * 2. cd [repo root]/examples * 3. Run in server mode: - * dapr run --app-id tracingdemo --app-port 3000 \ - * -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3000 + * dapr run --app-id tracing-tracingdemo --app-port 3380 \ + * -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3380 * 4. Run middle server: - * dapr run --app-id tracingdemoproxy --app-port 3001 \ - * -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3001 + * dapr run --app-id tracing-tracingdemoproxy --app-port 3381 \ + * -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3381 */ public class TracingDemoService { diff --git a/examples/src/main/java/io/dapr/examples/tracing/Validation.java b/examples/src/main/java/io/dapr/examples/tracing/Validation.java index 3180c5ab8a..50403a0f9a 100644 --- a/examples/src/main/java/io/dapr/examples/tracing/Validation.java +++ b/examples/src/main/java/io/dapr/examples/tracing/Validation.java @@ -47,16 +47,16 @@ final class Validation { .build(); public static final String JSONPATH_PROXY_ECHO_SPAN_ID = - "$..[?(@.parentId=='%s' && @.name=='calllocal/tracingdemoproxy/proxy_echo')]['id']"; + "$..[?(@.parentId=='%s' && @.name=='calllocal/tracing-tracingdemoproxy/proxy_echo')]['id']"; public static final String JSONPATH_ECHO_SPAN_ID = - "$..[?(@.parentId=='%s' && @.name=='calllocal/tracingdemo/echo')]['id']"; + "$..[?(@.parentId=='%s' && @.name=='calllocal/tracing-tracingdemo/echo')]['id']"; public static final String JSONPATH_PROXY_SLEEP_SPAN_ID = - "$..[?(@.parentId=='%s' && @.duration > 1000000 && @.name=='calllocal/tracingdemoproxy/proxy_sleep')]['id']"; + "$..[?(@.parentId=='%s' && @.duration > 1000000 && @.name=='calllocal/tracing-tracingdemoproxy/proxy_sleep')]['id']"; public static final String JSONPATH_SLEEP_SPAN_ID = - "$..[?(@.parentId=='%s' && @.duration > 1000000 && @.name=='calllocal/tracingdemo/sleep')]['id']"; + "$..[?(@.parentId=='%s' && @.duration > 1000000 && @.name=='calllocal/tracing-tracingdemo/sleep')]['id']"; static void validate() { Status result = new CallExecutorBuilder().config(RETRY_CONFIG).build().execute(() -> doValidate()); 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 167a423d5d..7d19611483 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/README.md +++ b/examples/src/main/java/io/dapr/examples/workflows/README.md @@ -148,7 +148,7 @@ background: true --> Execute the following script in order to run DemoChainWorker: ```sh -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 +dapr run --app-id workflows-chainingworker --resources-path ./components/workflows --dapr-grpc-port 3420 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.chain.DemoChainWorker 3420 ``` Once running, the logs will start displaying the different steps: First, you can see workflow is starting: @@ -170,8 +170,8 @@ timeout_seconds: 20 --> Then, execute the following script in order to run DemoChainClient: ```sh -java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.chain.DemoChainClient 50001 -dapr stop --app-id chainingworker +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.chain.DemoChainClient 3420 +dapr stop --app-id workflows-chainingworker ``` @@ -268,7 +268,7 @@ background: true Execute the following script in order to run DemoFanInOutWorker: ```sh -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 +dapr run --app-id workflows-faninoutworker --resources-path ./components/workflows --dapr-grpc-port 3421 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.faninout.DemoFanInOutWorker 3421 ``` @@ -284,8 +284,8 @@ timeout_seconds: 20 Execute the following script in order to run DemoFanInOutClient: ```sh -java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.faninout.DemoFanInOutClient 50002 -dapr stop --app-id faninoutworker +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.faninout.DemoFanInOutClient 3421 +dapr stop --app-id workflows-faninoutworker ``` @@ -370,7 +370,7 @@ public class CleanUpActivity implements WorkflowActivity { Once you start the workflow and client using the following commands: ```sh -dapr run --app-id demoworkflowworker --resources-path ./components/workflows -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.continueasnew.DemoContinueAsNewWorker +dapr run --app-id workflows-demoworkflowworker --resources-path ./components/workflows -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.continueasnew.DemoContinueAsNewWorker ``` ```sh java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.continueasnew.DemoContinueAsNewClient @@ -441,7 +441,7 @@ client.raiseEvent(instanceId, "Approval", true); Start the workflow and client using the following commands: ```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 +dapr run --app-id workflows-demoworkflowworker --resources-path ./components/workflows -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.externalevent.DemoExternalEventWorker ``` ```sh @@ -534,7 +534,7 @@ 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.childworkflow.DemoChildWorkflowWorker +dapr run --app-id workflows-demoworkflowworker --resources-path ./components/workflows -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.childworkflow.DemoChildWorkflowWorker ``` ```sh @@ -648,7 +648,7 @@ timeout_seconds: 30 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 50003 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.compensation.BookTripWorker 50003 +dapr run --app-id workflows-book-trip-worker --resources-path ./components/workflows --dapr-grpc-port 3422 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.compensation.BookTripWorker 3422 ``` @@ -663,8 +663,8 @@ timeout_seconds: 30 --> 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 50003 -dapr stop --app-id book-trip-worker +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.compensation.BookTripClient 3422 +dapr stop --app-id workflows-book-trip-worker ``` @@ -793,17 +793,17 @@ This example requires running multiple Dapr applications simultaneously. You'll 1. **Start the main workflow worker (multiapp-worker):** ```sh -dapr run --app-id multiapp-worker --resources-path ./components/workflows --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.MultiAppWorker +dapr run --app-id workflows-multiapp-worker --resources-path ./components/workflows --dapr-grpc-port 3423 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.MultiAppWorker ``` 2. **Start app2 worker (handles App2TransformActivity):** ```sh -dapr run --app-id app2 --resources-path ./components/workflows --dapr-grpc-port 50002 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.App2Worker +dapr run --app-id workflows-app2 --resources-path ./components/workflows --dapr-grpc-port 3424 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.App2Worker ``` 3. **Start app3 worker (handles App3FinalizeActivity):** ```sh -dapr run --app-id app3 --resources-path ./components/workflows --dapr-grpc-port 50003 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.App3Worker +dapr run --app-id workflows-app3 --resources-path ./components/workflows --dapr-grpc-port 3425 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.App3Worker ``` 4. **Run the workflow client:** @@ -891,7 +891,7 @@ background: true --> Execute the following script to run DemoHistoryPropagationWorker: ```sh -dapr run --app-id historypropagationworker --resources-path ./components/workflows --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.historypropagation.DemoHistoryPropagationWorker 50001 +dapr run --app-id workflows-historypropagationworker --resources-path ./components/workflows --dapr-grpc-port 3426 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.historypropagation.DemoHistoryPropagationWorker 3426 ``` @@ -906,8 +906,8 @@ timeout_seconds: 60 --> Execute the following script to run DemoHistoryPropagationClient: ```sh -java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.historypropagation.DemoHistoryPropagationClient 50001 -dapr stop --app-id historypropagationworker +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.historypropagation.DemoHistoryPropagationClient 3426 +dapr stop --app-id workflows-historypropagationworker ``` @@ -946,7 +946,7 @@ timeout_seconds: 30 --> ```sh -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 +dapr run --app-id workflows-suspendresumeworker --resources-path ./components/workflows --dapr-grpc-port 3427 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeWorker 3427 ``` @@ -964,8 +964,8 @@ expected_stdout_lines: timeout_seconds: 30 --> ```sh -java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeClient 50004 -dapr stop --app-id suspendresumeworker +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.suspendresume.DemoSuspendResumeClient 3427 +dapr stop --app-id workflows-suspendresumeworker ``` diff --git a/examples/src/main/java/io/dapr/examples/workflows/multiapp/MultiAppWorkflow.java b/examples/src/main/java/io/dapr/examples/workflows/multiapp/MultiAppWorkflow.java index b45dfe9f0d..cc46a67470 100644 --- a/examples/src/main/java/io/dapr/examples/workflows/multiapp/MultiAppWorkflow.java +++ b/examples/src/main/java/io/dapr/examples/workflows/multiapp/MultiAppWorkflow.java @@ -41,7 +41,7 @@ public WorkflowStub create() { String multiAppResult = ctx.callActivity( App2TransformActivity.class.getName(), input, - new WorkflowTaskOptions("app2"), + new WorkflowTaskOptions("workflows-app2"), String.class ).await(); @@ -51,7 +51,7 @@ public WorkflowStub create() { String finalResult = ctx.callActivity( App3FinalizeActivity.class.getName(), multiAppResult, - new WorkflowTaskOptions("app3"), + new WorkflowTaskOptions("workflows-app3"), String.class ).await(); logger.info("Final multi-app activity result: {}", finalResult); diff --git a/examples/validate/check-parallel-safe.sh b/examples/validate/check-parallel-safe.sh new file mode 100755 index 0000000000..ef0e4e17fa --- /dev/null +++ b/examples/validate/check-parallel-safe.sh @@ -0,0 +1,309 @@ +#!/usr/bin/env bash +# check-parallel-safe.sh +# +# Statically checks that Dapr example READMEs follow the "parallel-safe" standard +# so they can all run concurrently against one shared Dapr runtime. +# +# Rules enforced: +# 1. Every --app-id must start with "-" or equal "" exactly, where +# is the README's path under examples/src/main/java/io/dapr/examples/ +# with '/' replaced by '-' and the trailing /README.md removed. +# 2. No line may use the default --dapr-http-port 3500 or --dapr-grpc-port 50001. +# 3. Every --app-port value must be unique across all READMEs in the list. +# 4. Every app-id in a component YAML's "scopes:" list (under examples/components) +# must equal, or start with "-" for, a known example slug. +# +# Portable: macOS bash 3.2 and Linux bash. No associative arrays, no mapfile. + +set -u + +# --------------------------------------------------------------------------- +# Resolve repo root / examples dir from this script's own location, not cwd. +# Script lives at: examples/validate/check-parallel-safe.sh +# --------------------------------------------------------------------------- +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +EXAMPLES_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +LIST_FILE="$SCRIPT_DIR/readmes.txt" + +usage() { + echo "Usage: $0 [-f FILE] [README_PATH ...]" >&2 + echo " -f FILE override the list of README paths (default: $LIST_FILE)" >&2 + echo " README_PATH ... optional positional README paths (relative to examples/)" >&2 +} + +# --------------------------------------------------------------------------- +# Argument parsing +# --------------------------------------------------------------------------- +while getopts "f:h" opt; do + case "$opt" in + f) + LIST_FILE="$OPTARG" + ;; + h) + usage + exit 0 + ;; + *) + usage + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +# --------------------------------------------------------------------------- +# Build the list of README paths (relative to $EXAMPLES_DIR) to check. +# Positional args (if any) take precedence over the list file. +# --------------------------------------------------------------------------- +README_LIST_TMP="$(mktemp)" +trap 'rm -f "$README_LIST_TMP"' EXIT + +if [ "$#" -gt 0 ]; then + for arg in "$@"; do + printf '%s\n' "$arg" >> "$README_LIST_TMP" + done +else + if [ ! -f "$LIST_FILE" ]; then + echo "error: list file not found: $LIST_FILE" >&2 + exit 2 + fi + # Strip blank lines and '#' comment lines. + while IFS= read -r line || [ -n "$line" ]; do + # Trim leading/trailing whitespace. + trimmed="$(printf '%s' "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + [ -z "$trimmed" ] && continue + case "$trimmed" in + \#*) continue ;; + esac + printf '%s\n' "$trimmed" >> "$README_LIST_TMP" + done < "$LIST_FILE" +fi + +if [ ! -s "$README_LIST_TMP" ]; then + echo "error: no README paths to check" >&2 + exit 2 +fi + +# --------------------------------------------------------------------------- +# Derive slug from a README path (relative to examples/src/main/java/io/dapr/examples/). +# e.g. pubsub/README.md -> pubsub +# invoke/http/README.md -> invoke-http +# pubsub/stream/README.md -> pubsub-stream +# --------------------------------------------------------------------------- +slug_for() { + rel_path="$1" + prefix="src/main/java/io/dapr/examples/" + case "$rel_path" in + "$prefix"*) + trimmed="${rel_path#"$prefix"}" + ;; + *) + trimmed="$rel_path" + ;; + esac + trimmed="${trimmed%/README.md}" + printf '%s\n' "$trimmed" | tr '/' '-' +} + +# --------------------------------------------------------------------------- +# Pass 1: for each README, extract every "--app-port " occurrence (with +# line number) into a global scratch file, tagged with the README path. +# Format per line: "\t\t" +# --------------------------------------------------------------------------- +APP_PORTS_TMP="$(mktemp)" +trap 'rm -f "$README_LIST_TMP" "$APP_PORTS_TMP"' EXIT + +VIOLATIONS_TMP="$(mktemp)" +trap 'rm -f "$README_LIST_TMP" "$APP_PORTS_TMP" "$VIOLATIONS_TMP"' EXIT + +VALID_README_LIST_TMP="$(mktemp)" +trap 'rm -f "$README_LIST_TMP" "$APP_PORTS_TMP" "$VIOLATIONS_TMP" "$VALID_README_LIST_TMP"' EXIT + +violation_count=0 +affected_files_tmp="$(mktemp)" +trap 'rm -f "$README_LIST_TMP" "$APP_PORTS_TMP" "$VIOLATIONS_TMP" "$VALID_README_LIST_TMP" "$affected_files_tmp"' EXIT + +add_violation() { + printf '%s\n' "$1" >> "$VIOLATIONS_TMP" + violation_count=$((violation_count + 1)) +} + +while IFS= read -r readme_rel || [ -n "$readme_rel" ]; do + [ -z "$readme_rel" ] && continue + readme_abs="$EXAMPLES_DIR/$readme_rel" + if [ ! -f "$readme_abs" ]; then + echo "warning: README not found, skipping: $readme_rel" >&2 + continue + fi + printf '%s\n' "$readme_rel" >> "$VALID_README_LIST_TMP" + + # --- Rule 1: app-id prefix ------------------------------------------- + slug="$(slug_for "$readme_rel")" + + while IFS=: read -r line_no line_content; do + [ -z "$line_no" ] && continue + # Pull each "--app-id " occurrence out of the line. + remainder="$line_content" + while :; do + case "$remainder" in + *--app-id*) + after="${remainder#*--app-id}" + # Skip leading whitespace (spaces or '='). + after_trimmed="$(printf '%s' "$after" | sed -e 's/^[[:space:]=]*//')" + app_id="$(printf '%s' "$after_trimmed" | awk '{print $1}')" + # Strip surrounding markdown backticks/punctuation, e.g. from + # prose like "with distinct `--app-id` and `--dapr-grpc-port`". + app_id="$(printf '%s' "$app_id" | sed -e 's/^`*//' -e 's/[`,.;:)]*$//')" + if [ -n "$app_id" ]; then + if [ "$app_id" = "$slug" ]; then + : + else + case "$app_id" in + "$slug"-*) : ;; + *) + add_violation "$readme_rel:$line_no: app-id '$app_id' must start with '$slug-'" + ;; + esac + fi + fi + remainder="$after_trimmed" + ;; + *) + break + ;; + esac + done + done < <(grep -n -- "--app-id" "$readme_abs" 2>/dev/null) + + # --- Rule 2: no default dapr ports ----------------------------------- + while IFS=: read -r line_no line_content; do + [ -z "$line_no" ] && continue + case "$line_content" in + *--dapr-http-port\ 3500*) + add_violation "$readme_rel:$line_no: default dapr port 3500 collides under concurrency; use a unique port or omit the flag" + ;; + esac + done < <(grep -n -- "--dapr-http-port 3500" "$readme_abs" 2>/dev/null) + + while IFS=: read -r line_no line_content; do + [ -z "$line_no" ] && continue + case "$line_content" in + *--dapr-grpc-port\ 50001*) + add_violation "$readme_rel:$line_no: default dapr port 50001 collides under concurrency; use a unique port or omit the flag" + ;; + esac + done < <(grep -n -- "--dapr-grpc-port 50001" "$readme_abs" 2>/dev/null) + + # --- Collect app-port occurrences for the cross-README uniqueness check. + while IFS=: read -r line_no line_content; do + [ -z "$line_no" ] && continue + remainder="$line_content" + while :; do + case "$remainder" in + *--app-port*) + after="${remainder#*--app-port}" + after_trimmed="$(printf '%s' "$after" | sed -e 's/^[[:space:]=]*//')" + port="$(printf '%s' "$after_trimmed" | awk '{print $1}')" + if [ -n "$port" ]; then + printf '%s\t%s\t%s\n' "$readme_rel" "$line_no" "$port" >> "$APP_PORTS_TMP" + fi + remainder="$after_trimmed" + ;; + *) + break + ;; + esac + done + done < <(grep -n -- "--app-port" "$readme_abs" 2>/dev/null) + +done < "$README_LIST_TMP" + +# --------------------------------------------------------------------------- +# Rule 3: --app-port cross-README uniqueness. +# For every distinct port value, find the set of distinct READMEs that use it. +# If more than one README uses it, every occurrence of that port (in every +# README that uses it) is a violation, listing the *other* README(s). +# --------------------------------------------------------------------------- +if [ -s "$APP_PORTS_TMP" ]; then + distinct_ports="$(cut -f3 "$APP_PORTS_TMP" | sort -u)" + while IFS= read -r port; do + [ -z "$port" ] && continue + readmes_for_port="$(awk -F'\t' -v p="$port" '$3 == p {print $1}' "$APP_PORTS_TMP" | sort -u)" + readme_count="$(printf '%s\n' "$readmes_for_port" | sed '/^$/d' | wc -l | tr -d ' ')" + if [ "$readme_count" -gt 1 ]; then + while IFS=$'\t' read -r r_readme r_line r_port; do + [ -z "$r_readme" ] && continue + [ "$r_port" != "$port" ] && continue + others="$(printf '%s\n' "$readmes_for_port" | grep -v -F -x "$r_readme" | sort -u | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g')" + add_violation "$r_readme:$r_line: --app-port $port is also used by $others" + done < "$APP_PORTS_TMP" + fi + done < is not found"). Flag any scope entry that is not +# equal to, and does not start with "-" for, a known example slug. +# --------------------------------------------------------------------------- +KNOWN_SLUGS_TMP="$(mktemp)" +SCOPE_ENTRIES_TMP="$(mktemp)" +trap 'rm -f "$README_LIST_TMP" "$APP_PORTS_TMP" "$VIOLATIONS_TMP" "$VALID_README_LIST_TMP" "$affected_files_tmp" "$KNOWN_SLUGS_TMP" "$SCOPE_ENTRIES_TMP"' EXIT + +while IFS= read -r readme_rel || [ -n "$readme_rel" ]; do + [ -z "$readme_rel" ] && continue + slug_for "$readme_rel" +done < "$VALID_README_LIST_TMP" | sort -u > "$KNOWN_SLUGS_TMP" + +if [ -d "$EXAMPLES_DIR/components" ]; then + : > "$SCOPE_ENTRIES_TMP" + for sf in $(grep -rl -- "scopes:" "$EXAMPLES_DIR/components" 2>/dev/null); do + awk -v f="$sf" ' + /^scopes:[[:space:]]*$/ { inscope = 1; next } + inscope == 1 && /^[[:space:]]*-[[:space:]]/ { + e = $0 + sub(/^[[:space:]]*-[[:space:]]*/, "", e) + sub(/[[:space:]]+$/, "", e) + if (e != "") print f "\t" NR "\t" e + next + } + inscope == 1 && /^[^[:space:]#-]/ { inscope = 0 } + ' "$sf" >> "$SCOPE_ENTRIES_TMP" + done + + while IFS=$'\t' read -r s_file s_line s_appid; do + [ -z "$s_appid" ] && continue + valid=0 + while IFS= read -r g; do + [ -z "$g" ] && continue + if [ "$s_appid" = "$g" ]; then valid=1; break; fi + case "$s_appid" in "$g"-*) valid=1; break ;; esac + done < "$KNOWN_SLUGS_TMP" + if [ "$valid" -eq 0 ]; then + rel="${s_file#"$REPO_ROOT/"}" + add_violation "$rel:$s_line: scope app-id '$s_appid' is not prefixed with a known example slug (rename to match the migrated app-id)" + fi + done < "$SCOPE_ENTRIES_TMP" +fi + +# --------------------------------------------------------------------------- +# Output +# --------------------------------------------------------------------------- +if [ -s "$VIOLATIONS_TMP" ]; then + sort -t: -k1,1 -k2,2n "$VIOLATIONS_TMP" + cut -d: -f1 "$VIOLATIONS_TMP" | sort -u > "$affected_files_tmp" + affected_count="$(wc -l < "$affected_files_tmp" | tr -d ' ')" + echo "" + echo "Summary: $violation_count violation(s) across $affected_count README(s)." + exit 1 +else + echo "Summary: 0 violations. All checked READMEs are parallel-safe." + exit 0 +fi diff --git a/examples/validate/readmes.txt b/examples/validate/readmes.txt new file mode 100644 index 0000000000..20ae7b427e --- /dev/null +++ b/examples/validate/readmes.txt @@ -0,0 +1,17 @@ +src/main/java/io/dapr/examples/actors/README.md +src/main/java/io/dapr/examples/bindings/http/README.md +src/main/java/io/dapr/examples/configuration/README.md +src/main/java/io/dapr/examples/conversation/README.md +src/main/java/io/dapr/examples/crypto/README.md +src/main/java/io/dapr/examples/exception/README.md +src/main/java/io/dapr/examples/invoke/grpc/README.md +src/main/java/io/dapr/examples/invoke/http/README.md +src/main/java/io/dapr/examples/jobs/README.md +src/main/java/io/dapr/examples/pubsub/README.md +src/main/java/io/dapr/examples/pubsub/stream/README.md +src/main/java/io/dapr/examples/querystate/README.md +src/main/java/io/dapr/examples/secrets/README.md +src/main/java/io/dapr/examples/state/README.md +src/main/java/io/dapr/examples/tracing/README.md +src/main/java/io/dapr/examples/unittesting/README.md +src/main/java/io/dapr/examples/workflows/README.md diff --git a/examples/validate/run-parallel.sh b/examples/validate/run-parallel.sh new file mode 100755 index 0000000000..ca164589be --- /dev/null +++ b/examples/validate/run-parallel.sh @@ -0,0 +1,238 @@ +#!/usr/bin/env bash +# +# run-parallel.sh — run Dapr example READMEs through mm.py (mechanical-markdown) +# concurrently, from the correct working directory, with retries and a +# summary report at the end. +# +# Usage: +# run-parallel.sh [-j N] [-r R] [-f FILE] [--dry-run] [README ...] +# +# -j N Max concurrent READMEs (default 4). +# -r R Per-README retry count on failure (default 2, i.e. up to +# 3 attempts total). +# -f FILE README list file (default: examples/validate/readmes.txt +# resolved relative to the repo root). +# --dry-run Do not run mm.py; print the exact command that would run +# for each README instead. +# README ... Positional README paths (relative to the examples dir). +# If given, these override the list file. +# +# Portable: must work on macOS bash 3.2 and Linux bash. No associative +# arrays, no `wait -n`. + +set -u + +# --------------------------------------------------------------------------- +# Hidden subcommand: __run_one +# +# This script re-execs itself via `xargs -P N -I{} bash "$0" __run_one {} ...` +# to get a portable concurrency pool (no associative arrays / `wait -n` +# needed). When invoked this way, run a single README (with retries) and +# write its result to a per-README result file, then exit. +# --------------------------------------------------------------------------- +if [ "${1:-}" = "__run_one" ]; then + shift + readme="$1" + examples_dir="$2" + retries="$3" + log_dir="$4" + + slug=$(printf '%s' "$readme" | tr '/' '_') + log_file="$log_dir/${slug}.log" + result_file="$log_dir/${slug}.result" + + attempts=0 + max_attempts=$((retries + 1)) + start_ts=$(date +%s) + status="FAIL" + + : > "$log_file" + + while [ "$attempts" -lt "$max_attempts" ]; do + attempts=$((attempts + 1)) + { + echo "=== attempt $attempts/$max_attempts: (cd $examples_dir && mm.py $readme) ===" + } >> "$log_file" + + if (cd "$examples_dir" && mm.py "$readme") >> "$log_file" 2>&1; then + status="PASS" + break + fi + done + + end_ts=$(date +%s) + duration=$((end_ts - start_ts)) + + printf '%s\t%s\t%s\t%s\t%s\n' "$readme" "$status" "$attempts" "$duration" "$log_file" > "$result_file" + + if [ "$status" = "PASS" ]; then + exit 0 + else + exit 1 + fi +fi + +# --------------------------------------------------------------------------- +# Main entry point +# --------------------------------------------------------------------------- + +usage() { + cat <<'EOF' +Usage: run-parallel.sh [-j N] [-r R] [-f FILE] [--dry-run] [README ...] + + -j N Max concurrent READMEs (default 4). + -r R Per-README retry count on failure (default 1, i.e. up to + 2 attempts total). + -f FILE README list file (default: examples/validate/readmes.txt + resolved relative to the repo root). + --dry-run Do not run mm.py; print the exact command that would run + for each README instead. + README ... Positional README paths (relative to the examples dir). + If given, these override the list file. +EOF +} + +# Resolve script location, examples dir, and repo root from the script's +# own path -- not from the caller's cwd. +script_source="$0" +script_dir=$(cd "$(dirname "$script_source")" && pwd) +# script is at /examples/validate/run-parallel.sh +repo_root=$(cd "$script_dir/../.." && pwd) +examples_dir="$repo_root/examples" + +jobs=4 +retries=2 +list_file="$examples_dir/validate/readmes.txt" +dry_run=0 +positional_readmes=() + +while [ "$#" -gt 0 ]; do + case "$1" in + -j) + [ "$#" -ge 2 ] || { echo "run-parallel.sh: -j requires an argument" >&2; exit 2; } + jobs="$2" + shift 2 + ;; + -r) + [ "$#" -ge 2 ] || { echo "run-parallel.sh: -r requires an argument" >&2; exit 2; } + retries="$2" + shift 2 + ;; + -f) + [ "$#" -ge 2 ] || { echo "run-parallel.sh: -f requires an argument" >&2; exit 2; } + list_file="$2" + shift 2 + ;; + --dry-run) + dry_run=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + --) + shift + while [ "$#" -gt 0 ]; do + positional_readmes+=("$1") + shift + done + ;; + -*) + echo "run-parallel.sh: unknown option: $1" >&2 + usage >&2 + exit 2 + ;; + *) + positional_readmes+=("$1") + shift + ;; + esac +done + +# Build the list of READMEs to validate. +readmes=() +if [ "${#positional_readmes[@]}" -gt 0 ]; then + readmes=("${positional_readmes[@]}") +else + if [ ! -f "$list_file" ]; then + echo "run-parallel.sh: README list file not found: $list_file" >&2 + exit 2 + fi + while IFS= read -r line || [ -n "$line" ]; do + # Trim leading/trailing whitespace. + trimmed=$(printf '%s' "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') + [ -z "$trimmed" ] && continue + case "$trimmed" in + \#*) continue ;; + esac + readmes+=("$trimmed") + done < "$list_file" +fi + +if [ "${#readmes[@]}" -eq 0 ]; then + echo "run-parallel.sh: no READMEs to validate" >&2 + exit 2 +fi + +if [ "$dry_run" -eq 1 ]; then + for readme in "${readmes[@]}"; do + echo "(cd $examples_dir && mm.py $readme)" + done + exit 0 +fi + +log_dir=$(mktemp -d "${TMPDIR:-/tmp}/run-parallel.XXXXXX") + +# Run every README through the hidden __run_one subcommand, in parallel, +# via xargs -P. This avoids associative arrays and `wait -n`, keeping the +# script portable to macOS bash 3.2. +printf '%s\n' "${readmes[@]}" | \ + xargs -I{} -P "$jobs" bash "$script_source" __run_one {} "$examples_dir" "$retries" "$log_dir" + +# Collect results. Order the summary the same as the input list. +overall_status=0 +total_pass=0 +total_fail=0 + +echo +echo "==================== SUMMARY ====================" +printf '%-6s %-60s %-8s %-10s\n' "STATUS" "README" "ATTEMPTS" "DURATION(s)" + +for readme in "${readmes[@]}"; do + slug=$(printf '%s' "$readme" | tr '/' '_') + result_file="$log_dir/${slug}.result" + + if [ -f "$result_file" ]; then + IFS=$'\t' read -r r_readme r_status r_attempts r_duration r_log < "$result_file" + else + r_readme="$readme" + r_status="FAIL" + r_attempts="0" + r_duration="0" + r_log="$log_dir/${slug}.log" + fi + + printf '%-6s %-60s %-8s %-10s\n' "$r_status" "$r_readme" "$r_attempts" "$r_duration" + + if [ "$r_status" = "PASS" ]; then + total_pass=$((total_pass + 1)) + else + total_fail=$((total_fail + 1)) + overall_status=1 + + echo " --- log: $r_log" + if [ -f "$r_log" ]; then + echo " --- last 20 lines of $r_log ---" + tail -n 20 "$r_log" | sed 's/^/ /' + else + echo " (no log captured)" + fi + fi +done + +echo "===================================================" +echo "Total: ${#readmes[@]} Pass: $total_pass Fail: $total_fail" +echo "Logs directory: $log_dir" + +exit "$overall_status"