diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8fc0b023a..d3c936966 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,13 +1,15 @@
name: "Continuous Integration"
on: [push, pull_request]
+permissions:
+ contents: read
jobs:
validation:
name: "Gradle wrapper validation"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: gradle/wrapper-validation-action@v3
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: gradle/actions/wrapper-validation@ac396bf1a80af16236baf54bd7330ae21dc6ece5 # v6
unittest:
name: Unit Tests
@@ -15,7 +17,7 @@ jobs:
timeout-minutes: 15
steps:
- name: Checkout repo
- uses: actions/checkout@v4
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
submodules: recursive
@@ -23,7 +25,7 @@ jobs:
- name: Run unit tests
run: |
- docker compose -f ./docker/github/docker-compose.yaml up unit-test
+ docker compose -f ./docker/github/docker-compose.yaml up --exit-code-from unit-test unit-test
code_format:
name: Code format
@@ -31,20 +33,20 @@ jobs:
timeout-minutes: 20
steps:
- name: Checkout repo
- uses: actions/checkout@v4
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
submodules: recursive
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up Java
- uses: actions/setup-java@v4
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with:
java-version: "11"
distribution: "temurin"
- name: Set up Gradle
- uses: gradle/actions/setup-gradle@v3
+ uses: gradle/actions/setup-gradle@ac396bf1a80af16236baf54bd7330ae21dc6ece5 # v6
- name: Run copyright and code format checks
- run: ./gradlew --no-daemon spotlessCheck
\ No newline at end of file
+ run: ./gradlew --no-daemon spotlessCheck
diff --git a/.gitignore b/.gitignore
index a560c2465..038d5ef43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,4 +17,5 @@ target
.project
.settings/
bin/
-core/.vscode/
\ No newline at end of file
+core/.vscode/
+.claude/
diff --git a/README.md b/README.md
index a8af530f4..4d00e320b 100644
--- a/README.md
+++ b/README.md
@@ -79,7 +79,8 @@ See the README.md file in each main sample directory for cut/paste Gradle comman
- [**HelloDelayedStart**](/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java): Demonstrates how to use delayed start config option when starting a Workflow Executions.
- [**HelloSignalWithTimer**](/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java): Demonstrates how to use collect signals for certain amount of time and then process last one.
- [**HelloWorkflowTimer**](/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java): Demonstrates how we can use workflow timer to restrict duration of workflow execution instead of workflow run/execution timeouts.
-
+ - [**Auto-Heartbeating**](/core/src/main/java/io/temporal/samples/autoheartbeat/): Demonstrates use of Auto-heartbeating utility via activity interceptor.
+ - [**HelloSignalWithStartAndWorkflowInit**](/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java): Demonstrates how WorkflowInit can be useful with SignalWithStart to initialize workflow variables.
#### Scenario-based samples
@@ -105,6 +106,15 @@ See the README.md file in each main sample directory for cut/paste Gradle comman
- [**Safe Message Passing**](/core/src/main/java/io/temporal/samples/safemessagepassing): Safely handling concurrent updates and signals messages.
+- [**Custom Annotation**](/core/src/main/java/io/temporal/samples/customannotation): Demonstrates how to create a custom annotation using an interceptor.
+
+- [**Async Packet Delivery**](/core/src/main/java/io/temporal/samples/packetdelivery): Demonstrates running multiple execution paths async within single execution.
+
+- [**Worker Versioning**](/core/src/main/java/io/temporal/samples/workerversioning): Demonstrates how to use worker versioning to manage workflow code changes.
+
+- [**Environment Configuration**](/core/src/main/java/io/temporal/samples/envconfig):
+Load client configuration from TOML files with programmatic overrides.
+
#### API demonstrations
- [**Async Untyped Child Workflow**](/core/src/main/java/io/temporal/samples/asyncuntypedchild): Demonstrates how to invoke an untyped child workflow async, that can complete after parent workflow is already completed.
diff --git a/build.gradle b/build.gradle
index 6c5da619d..0cafde690 100644
--- a/build.gradle
+++ b/build.gradle
@@ -26,7 +26,7 @@ subprojects {
ext {
otelVersion = '1.30.1'
otelVersionAlpha = "${otelVersion}-alpha"
- javaSDKVersion = '1.30.0'
+ javaSDKVersion = '1.34.0'
camelVersion = '3.22.1'
jarVersion = '1.0.0'
}
diff --git a/core/build.gradle b/core/build.gradle
index 42ad4be2b..c5157db3d 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -4,7 +4,11 @@ dependencies {
implementation "io.temporal:temporal-opentracing:$javaSDKVersion"
testImplementation("io.temporal:temporal-testing:$javaSDKVersion")
+ // Environment configuration
+ implementation "io.temporal:temporal-envconfig:$javaSDKVersion"
+
// Needed for SDK related functionality
+ implementation "io.grpc:grpc-util"
implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.2"))
implementation "com.fasterxml.jackson.core:jackson-databind"
implementation "com.fasterxml.jackson.core:jackson-core"
diff --git a/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java b/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java
index 7425b88d6..2c4a326d4 100644
--- a/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java
+++ b/core/src/main/java/io/temporal/samples/apikey/ApiKeyWorker.java
@@ -2,15 +2,25 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowClientOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class ApiKeyWorker {
static final String TASK_QUEUE = "MyTaskQueue";
public static void main(String[] args) throws Exception {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
// For temporal cloud this would be ${cloud-region}.{cloud}.api.temporal.io:7233
// Example us-east-1.aws.api.temporal.io:7233
String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT");
@@ -24,10 +34,10 @@ public static void main(String[] args) throws Exception {
"TEMPORAL_ENDPOINT, TEMPORAL_NAMESPACE, and TEMPORAL_API_KEY environment variables must be set");
}
- // Create API Key enabled client
+ // Create API Key enabled client with environment config as base
WorkflowServiceStubs service =
WorkflowServiceStubs.newServiceStubs(
- WorkflowServiceStubsOptions.newBuilder()
+ WorkflowServiceStubsOptions.newBuilder(profile.toWorkflowServiceStubsOptions())
.setTarget(targetEndpoint)
.setEnableHttps(true)
.addApiKey(() -> apiKey)
@@ -36,7 +46,10 @@ public static void main(String[] args) throws Exception {
// Now setup and start workflow worker
WorkflowClient client =
WorkflowClient.newInstance(
- service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build());
+ service,
+ WorkflowClientOptions.newBuilder(profile.toWorkflowClientOptions())
+ .setNamespace(namespace)
+ .build());
// worker factory that can be used to create workers for specific task queues
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/apikey/Starter.java b/core/src/main/java/io/temporal/samples/apikey/Starter.java
index 60afe7c21..ac0fbce8c 100644
--- a/core/src/main/java/io/temporal/samples/apikey/Starter.java
+++ b/core/src/main/java/io/temporal/samples/apikey/Starter.java
@@ -3,10 +3,12 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowClientOptions;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class Starter {
@@ -14,6 +16,14 @@ public class Starter {
static final String WORKFLOW_ID = "HelloAPIKeyWorkflow";
public static void main(String[] args) throws Exception {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
// For temporal cloud this would be ${cloud-region}.{cloud}.api.temporal.io:7233
// Example us-east-1.aws.api.temporal.io:7233
String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT");
@@ -27,10 +37,10 @@ public static void main(String[] args) throws Exception {
"TEMPORAL_ENDPOINT, TEMPORAL_NAMESPACE, and TEMPORAL_API_KEY environment variables must be set");
}
- // Create API Key enabled client
+ // Create API Key enabled client with environment config as base
WorkflowServiceStubs service =
WorkflowServiceStubs.newServiceStubs(
- WorkflowServiceStubsOptions.newBuilder()
+ WorkflowServiceStubsOptions.newBuilder(profile.toWorkflowServiceStubsOptions())
.setTarget(targetEndpoint)
.setEnableHttps(true)
.addApiKey(() -> apiKey)
@@ -38,7 +48,10 @@ public static void main(String[] args) throws Exception {
WorkflowClient client =
WorkflowClient.newInstance(
- service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build());
+ service,
+ WorkflowClientOptions.newBuilder(profile.toWorkflowClientOptions())
+ .setNamespace(namespace)
+ .build());
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/asyncchild/Starter.java b/core/src/main/java/io/temporal/samples/asyncchild/Starter.java
index b02f0dc4c..339bd94fd 100644
--- a/core/src/main/java/io/temporal/samples/asyncchild/Starter.java
+++ b/core/src/main/java/io/temporal/samples/asyncchild/Starter.java
@@ -6,20 +6,32 @@
import io.temporal.api.workflowservice.v1.DescribeWorkflowExecutionResponse;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class Starter {
public static final String TASK_QUEUE = "asyncChildTaskQueue";
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
- private static final WorkerFactory factory = WorkerFactory.newInstance(client);
public static void main(String[] args) {
- createWorker();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+
+ createWorker(factory);
WorkflowOptions parentWorkflowOptions =
WorkflowOptions.newBuilder()
@@ -33,25 +45,28 @@ public static void main(String[] args) {
WorkflowExecution childWorkflowExecution = parentWorkflowStub.executeParent();
// Get the child workflow execution status (after parent completed)
- System.out.println("Child execution status: " + getStatusAsString(childWorkflowExecution));
+ System.out.println(
+ "Child execution status: " + getStatusAsString(childWorkflowExecution, client, service));
// Wait for child workflow to complete
sleep(4);
// Check the status of the child workflow again
- System.out.println("Child execution status: " + getStatusAsString(childWorkflowExecution));
+ System.out.println(
+ "Child execution status: " + getStatusAsString(childWorkflowExecution, client, service));
System.exit(0);
}
- private static void createWorker() {
+ private static void createWorker(WorkerFactory factory) {
Worker worker = factory.newWorker(TASK_QUEUE);
worker.registerWorkflowImplementationTypes(ParentWorkflowImpl.class, ChildWorkflowImpl.class);
factory.start();
}
- private static String getStatusAsString(WorkflowExecution execution) {
+ private static String getStatusAsString(
+ WorkflowExecution execution, WorkflowClient client, WorkflowServiceStubs service) {
DescribeWorkflowExecutionRequest describeWorkflowExecutionRequest =
DescribeWorkflowExecutionRequest.newBuilder()
.setNamespace(client.getOptions().getNamespace())
diff --git a/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java b/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java
index 6cf9da20f..885a0c05c 100644
--- a/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java
+++ b/core/src/main/java/io/temporal/samples/asyncuntypedchild/Starter.java
@@ -2,9 +2,11 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
/**
* Sample Temporal Workflow Definition that demonstrates the execution of a Child Workflow. Child
@@ -24,12 +26,21 @@ public class Starter {
public static void main(String[] args) {
// Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
/*
* Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
*/
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/AutoHeartbeatUtil.java b/core/src/main/java/io/temporal/samples/autoheartbeat/AutoHeartbeatUtil.java
new file mode 100644
index 000000000..ca2b0a5f4
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/AutoHeartbeatUtil.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.autoheartbeat;
+
+import io.temporal.activity.ActivityExecutionContext;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+public class AutoHeartbeatUtil {
+ private final long period;
+ private final long initialDelay;
+ private final TimeUnit periodTimeUnit;
+ private final ScheduledExecutorService timerService =
+ Executors.newSingleThreadScheduledExecutor();
+ private final ActivityExecutionContext context;
+ private final Object details;
+ private String heartbeaterId;
+
+ public AutoHeartbeatUtil(
+ long period,
+ long initialDelay,
+ TimeUnit periodTimeUnit,
+ ActivityExecutionContext context,
+ Object details) {
+ this.period = period;
+ this.initialDelay = initialDelay;
+ this.periodTimeUnit = periodTimeUnit;
+ this.context = context;
+ this.details = details;
+ // Set to activity id better, for sample we just use type
+ heartbeaterId = context.getInfo().getActivityType();
+ }
+
+ public ScheduledFuture> start() {
+ System.out.println("Autoheartbeater[" + heartbeaterId + "] starting...");
+ return timerService.scheduleAtFixedRate(
+ () -> {
+ // try {
+ System.out.println(
+ "Autoheartbeater["
+ + heartbeaterId
+ + "]"
+ + "heartbeating at: "
+ + printShortCurrentTime());
+ context.heartbeat(details);
+ },
+ initialDelay,
+ period,
+ periodTimeUnit);
+ }
+
+ public void stop() {
+ System.out.println("Autoheartbeater[" + heartbeaterId + "] being requested to stop.");
+ // Try not to execute another heartbeat that could have been queued up
+ // Note this can at times take a second or two so make sure to test this out on your workers
+ // So can set best heartbeat timeout (sometimes might need larger value to accomodate)
+ timerService.shutdownNow();
+ }
+
+ private String printShortCurrentTime() {
+ return DateTimeFormatter.ofPattern("HH:mm:ss")
+ .withZone(ZoneId.systemDefault())
+ .format(Instant.now());
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/README.md b/core/src/main/java/io/temporal/samples/autoheartbeat/README.md
new file mode 100644
index 000000000..946e24fc5
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/README.md
@@ -0,0 +1,21 @@
+# Auto-heartbeating sample for activities that define HeartbeatTimeout
+
+This sample shows an implementation of an "auto-heartbeating" utility that can be applied via interceptor to all
+activities where you define HeartbeatTimeout. Use case where this can be helpful include situations where you have
+long-running activities where you want to heartbeat but its difficult to explicitly call heartbeat api in activity code
+directly.
+Another useful scenario for this is where you have activity that at times can complete in very short amount of time,
+but then at times can take for example minutes. In this case you have to set longer StartToClose timeout
+but you might not want first heartbeat to be sent right away but send it after the "shorter" duration of activity
+execution.
+
+Warning: make sure to test this sample for your use case. This includes load testing. This sample was not
+tested on large scale workloads. In addition note that it is recommended to heartbeat from activity code itself. Using
+this type of autoheartbeating utility does have disatvantage that activity code itself can continue running after
+a handled activity cancelation. Please be aware of these warnings when applying this sample.
+
+1. Start the Sample:
+
+```bash
+./gradlew -q execute -PmainClass=io.temporal.samples.autoheartbeat.Starter
+```
\ No newline at end of file
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java b/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java
new file mode 100644
index 000000000..ae438cc41
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/Starter.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.autoheartbeat;
+
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.failure.CanceledFailure;
+import io.temporal.samples.autoheartbeat.activities.AutoActivitiesImpl;
+import io.temporal.samples.autoheartbeat.interceptor.AutoHeartbeatWorkerInterceptor;
+import io.temporal.samples.autoheartbeat.workflows.AutoWorkflow;
+import io.temporal.samples.autoheartbeat.workflows.AutoWorkflowImpl;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerFactory;
+import io.temporal.worker.WorkerFactoryOptions;
+import java.io.IOException;
+
+public class Starter {
+ static final String TASK_QUEUE = "AutoheartbeatTaskQueue";
+ static final String WORKFLOW_ID = "AutoHeartbeatWorkflow";
+
+ public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+
+ // Configure our auto heartbeat workflow interceptor which will apply
+ // AutoHeartbeaterUtil to each activity workflow schedules which has a heartbeat
+ // timeout configured
+ WorkerFactoryOptions wfo =
+ WorkerFactoryOptions.newBuilder()
+ .setWorkerInterceptors(new AutoHeartbeatWorkerInterceptor())
+ .build();
+
+ WorkerFactory factory = WorkerFactory.newInstance(client, wfo);
+ Worker worker = factory.newWorker(TASK_QUEUE);
+
+ worker.registerWorkflowImplementationTypes(AutoWorkflowImpl.class);
+ worker.registerActivitiesImplementations(new AutoActivitiesImpl());
+
+ factory.start();
+
+ // first run completes execution with autoheartbeat utils
+ firstRun(client);
+ // second run cancels running (pending) activity via signal (specific scope cancel)
+ secondRun(client);
+ // third run cancels running execution which cancels activity as well
+ thirdRun(client);
+ // fourth run turns off autoheartbeat for activities and lets activity time out on heartbeat
+ // timeout
+ fourthRun(client);
+
+ System.exit(0);
+ }
+
+ @SuppressWarnings("unused")
+ private static void firstRun(WorkflowClient client) {
+ System.out.println("**** First Run: run workflow to completion");
+ AutoWorkflow firstRun =
+ client.newWorkflowStub(
+ AutoWorkflow.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId(WORKFLOW_ID)
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+
+ try {
+ String firstRunResult = firstRun.exec("Auto heartbeating is cool");
+ System.out.println("First run result: " + firstRunResult);
+ } catch (Exception e) {
+ System.out.println("First run - Workflow exec exception: " + e.getClass().getName());
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void secondRun(WorkflowClient client) {
+ System.out.println("\n\n**** Second Run: cancel activities via signal");
+ AutoWorkflow secondRun =
+ client.newWorkflowStub(
+ AutoWorkflow.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId(WORKFLOW_ID)
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+ WorkflowClient.start(secondRun::exec, "Auto heartbeating is cool");
+ doSleeps(4);
+ secondRun.cancelActivity();
+
+ try {
+ String secondRunResult = WorkflowStub.fromTyped(secondRun).getResult(String.class);
+ System.out.println("Second run result: " + secondRunResult);
+ } catch (Exception e) {
+ System.out.println("Second run - Workflow exec exception: " + e.getClass().getName());
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void thirdRun(WorkflowClient client) {
+ System.out.println("\n\n**** Third Run: cancel workflow execution");
+ AutoWorkflow thirdRun =
+ client.newWorkflowStub(
+ AutoWorkflow.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId(WORKFLOW_ID)
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+ WorkflowClient.start(thirdRun::exec, "Auto heartbeating is cool");
+ doSleeps(10);
+ try {
+ WorkflowStub.fromTyped(thirdRun).cancel();
+ String thirdRunResult = WorkflowStub.fromTyped(thirdRun).getResult(String.class);
+ System.out.println("Third run result: " + thirdRunResult);
+ } catch (Exception e) {
+ // we are expecting workflow cancelation
+ if (e.getCause() instanceof CanceledFailure) {
+ System.out.println("Third run - Workflow execution canceled.");
+ } else {
+ System.out.println("Third run - Workflow exec exception: " + e.getMessage());
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void fourthRun(WorkflowClient client) {
+ System.out.println("\n\n**** Fourth Run: cause heartbeat timeout");
+ // we disable autoheartbeat via env var
+ System.setProperty("sample.disableAutoHeartbeat", "true");
+ AutoWorkflow fourth =
+ client.newWorkflowStub(
+ AutoWorkflow.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId(WORKFLOW_ID)
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+
+ try {
+ String fourthRunResult = fourth.exec("Auto heartbeating is cool");
+ System.out.println("Fourth run result: " + fourthRunResult);
+ } catch (Exception e) {
+ System.out.println("Fourth run - Workflow exec exception: " + e.getClass().getName());
+ }
+ }
+
+ private static void doSleeps(int seconds) {
+ try {
+ Thread.sleep(seconds * 1000L);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivities.java b/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivities.java
new file mode 100644
index 000000000..81726e05a
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivities.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.autoheartbeat.activities;
+
+import io.temporal.activity.ActivityInterface;
+
+@ActivityInterface
+public interface AutoActivities {
+ String runActivityOne(String input);
+
+ String runActivityTwo(String input);
+}
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivitiesImpl.java b/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivitiesImpl.java
new file mode 100644
index 000000000..26a30162d
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/activities/AutoActivitiesImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.autoheartbeat.activities;
+
+import java.util.concurrent.TimeUnit;
+
+public class AutoActivitiesImpl implements AutoActivities {
+
+ @Override
+ public String runActivityOne(String input) {
+ return runActivity("runActivityOne - " + input, 10);
+ }
+
+ @Override
+ public String runActivityTwo(String input) {
+ return runActivity("runActivityTwo - " + input, 5);
+ }
+
+ @SuppressWarnings("FutureReturnValueIgnored")
+ private String runActivity(String input, int seconds) {
+ for (int i = 0; i < seconds; i++) {
+ sleep(1);
+ }
+ return "Activity completed: " + input;
+ }
+
+ private void sleep(int seconds) {
+ try {
+ Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
+ } catch (InterruptedException ee) {
+ // Empty
+ }
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatActivityInboundCallsInterceptor.java b/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatActivityInboundCallsInterceptor.java
new file mode 100644
index 000000000..60a2d5427
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatActivityInboundCallsInterceptor.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.autoheartbeat.interceptor;
+
+import io.temporal.activity.Activity;
+import io.temporal.activity.ActivityExecutionContext;
+import io.temporal.client.ActivityCanceledException;
+import io.temporal.common.interceptors.ActivityInboundCallsInterceptor;
+import io.temporal.common.interceptors.ActivityInboundCallsInterceptorBase;
+import io.temporal.samples.autoheartbeat.AutoHeartbeatUtil;
+import java.time.Duration;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+public class AutoHeartbeatActivityInboundCallsInterceptor
+ extends ActivityInboundCallsInterceptorBase {
+ private ActivityExecutionContext activityExecutionContext;
+ private Duration activityHeartbeatTimeout;
+ private AutoHeartbeatUtil autoHeartbeater;
+ private ScheduledFuture scheduledFuture;
+
+ public AutoHeartbeatActivityInboundCallsInterceptor(ActivityInboundCallsInterceptor next) {
+ super(next);
+ }
+
+ @Override
+ public void init(ActivityExecutionContext context) {
+ this.activityExecutionContext = context;
+ activityHeartbeatTimeout = activityExecutionContext.getInfo().getHeartbeatTimeout();
+ super.init(context);
+ }
+
+ @Override
+ @SuppressWarnings({"FutureReturnValueIgnored", "CatchAndPrintStackTrace"})
+ public ActivityOutput execute(ActivityInput input) {
+ // If activity has heartbeat timeout defined we want to apply auto-heartbeter
+ // Unless we explicitly disabled autoheartbeating via system property
+ if (activityHeartbeatTimeout != null
+ && activityHeartbeatTimeout.getSeconds() > 0
+ && !Boolean.parseBoolean(System.getProperty("sample.disableAutoHeartbeat"))) {
+ System.out.println(
+ "Auto heartbeating applied for activity: "
+ + activityExecutionContext.getInfo().getActivityType());
+ autoHeartbeater =
+ new AutoHeartbeatUtil(2, 0, TimeUnit.SECONDS, activityExecutionContext, input);
+ scheduledFuture = autoHeartbeater.start();
+ } else {
+ System.out.println(
+ "Auto heartbeating not being applied for activity: "
+ + activityExecutionContext.getInfo().getActivityType());
+ }
+
+ if (scheduledFuture != null) {
+ CompletableFuture activityExecFuture =
+ CompletableFuture.supplyAsync(() -> super.execute(input));
+ CompletableFuture autoHeartbeatFuture =
+ CompletableFuture.supplyAsync(
+ () -> {
+ try {
+ return scheduledFuture.get();
+ } catch (Exception e) {
+ throw new ActivityCanceledException(activityExecutionContext.getInfo());
+ }
+ });
+ try {
+ return (ActivityOutput)
+ CompletableFuture.anyOf(autoHeartbeatFuture, activityExecFuture).get();
+ } catch (Exception e) {
+ if (e instanceof ExecutionException) {
+ ExecutionException ee = (ExecutionException) e;
+ if (ee.getCause() instanceof ActivityCanceledException) {
+ throw new ActivityCanceledException(activityExecutionContext.getInfo());
+ }
+ }
+ throw Activity.wrap(e);
+ } finally {
+ if (autoHeartbeater != null) {
+ autoHeartbeater.stop();
+ }
+ }
+ } else {
+ return super.execute(input);
+ }
+ }
+
+ public interface AutoHeartbeaterCancellationCallback {
+ void handle(Exception e);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatWorkerInterceptor.java b/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatWorkerInterceptor.java
new file mode 100644
index 000000000..9816fe644
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/interceptor/AutoHeartbeatWorkerInterceptor.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.autoheartbeat.interceptor;
+
+import io.temporal.common.interceptors.ActivityInboundCallsInterceptor;
+import io.temporal.common.interceptors.WorkerInterceptorBase;
+
+public class AutoHeartbeatWorkerInterceptor extends WorkerInterceptorBase {
+ @Override
+ public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) {
+ return new AutoHeartbeatActivityInboundCallsInterceptor(next);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflow.java b/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflow.java
new file mode 100644
index 000000000..e8816c6a2
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflow.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.autoheartbeat.workflows;
+
+import io.temporal.workflow.SignalMethod;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+
+@WorkflowInterface
+public interface AutoWorkflow {
+ @WorkflowMethod
+ String exec(String input);
+
+ @SignalMethod
+ void cancelActivity();
+}
diff --git a/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflowImpl.java b/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflowImpl.java
new file mode 100644
index 000000000..6ff8100eb
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/autoheartbeat/workflows/AutoWorkflowImpl.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.autoheartbeat.workflows;
+
+import io.temporal.activity.ActivityCancellationType;
+import io.temporal.activity.ActivityOptions;
+import io.temporal.common.RetryOptions;
+import io.temporal.failure.ActivityFailure;
+import io.temporal.failure.CanceledFailure;
+import io.temporal.failure.TimeoutFailure;
+import io.temporal.samples.autoheartbeat.activities.AutoActivities;
+import io.temporal.workflow.CancellationScope;
+import io.temporal.workflow.Workflow;
+import java.time.Duration;
+
+public class AutoWorkflowImpl implements AutoWorkflow {
+ private CancellationScope scope;
+
+ @Override
+ public String exec(String input) {
+ AutoActivities activitiesOne =
+ Workflow.newActivityStub(
+ AutoActivities.class,
+ ActivityOptions.newBuilder()
+ .setStartToCloseTimeout(Duration.ofSeconds(22))
+ .setHeartbeatTimeout(Duration.ofSeconds(8))
+ .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED)
+ // for sample purposes
+ .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(3).build())
+ .build());
+
+ AutoActivities activitiesTwo =
+ Workflow.newActivityStub(
+ AutoActivities.class,
+ ActivityOptions.newBuilder()
+ .setStartToCloseTimeout(Duration.ofSeconds(20))
+ .setHeartbeatTimeout(Duration.ofSeconds(7))
+ .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED)
+ // for sample purposes
+ .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(3).build())
+ .build());
+
+ // Start our activity in CancellationScope so we can cancel it if needed
+ scope =
+ Workflow.newCancellationScope(
+ () -> {
+ activitiesOne.runActivityOne(input);
+ activitiesTwo.runActivityTwo(input);
+ });
+
+ try {
+ scope.run();
+ } catch (ActivityFailure e) {
+ if (e.getCause() instanceof CanceledFailure) {
+ // We dont want workflow to fail in we canceled our scope, just log and return
+ return "Workflow result after activity cancellation";
+ } else if (e.getCause() instanceof TimeoutFailure) {
+ return "Workflow result after activity timeout of type: "
+ + ((TimeoutFailure) e.getCause()).getTimeoutType().name();
+ } else {
+ throw e;
+ }
+ }
+ return "completed";
+ }
+
+ @Override
+ public void cancelActivity() {
+ scope.cancel("Canceling scope from signal handler");
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java
index 89bb5652c..90dcb7c10 100644
--- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java
+++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java
@@ -5,14 +5,26 @@
import io.temporal.api.common.v1.WorkflowExecution;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
/** Starts a single execution of HeartbeatingActivityBatchWorkflow. */
public class HeartbeatingActivityBatchStarter {
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient workflowClient = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient workflowClient =
+ WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build();
HeartbeatingActivityBatchWorkflow batchWorkflow =
workflowClient.newWorkflowStub(HeartbeatingActivityBatchWorkflow.class, options);
diff --git a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java
index 9d2d7b4e1..cd63bacf5 100644
--- a/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java
+++ b/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java
@@ -1,9 +1,11 @@
package io.temporal.samples.batch.heartbeatingactivity;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
/**
* A worker process that hosts implementations of HeartbeatingActivityBatchWorkflow and
@@ -14,8 +16,17 @@ public final class HeartbeatingActivityBatchWorker {
static final String TASK_QUEUE = "HeartbeatingActivityBatch";
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker(TASK_QUEUE);
diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java
index c89fc590c..fa43c467f 100644
--- a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java
+++ b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java
@@ -5,14 +5,26 @@
import io.temporal.api.common.v1.WorkflowExecution;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
/** Starts a single execution of IteratorBatchWorkflow. */
public class IteratorBatchStarter {
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient workflowClient = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient workflowClient =
+ WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build();
IteratorBatchWorkflow batchWorkflow =
workflowClient.newWorkflowStub(IteratorBatchWorkflow.class, options);
diff --git a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java
index 88b8eacb7..adc023d7b 100644
--- a/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java
+++ b/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java
@@ -1,9 +1,11 @@
package io.temporal.samples.batch.iterator;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
/**
* A worker process that hosts implementations of IteratorBatchWorkflow and RecordProcessorWorkflow
@@ -14,8 +16,17 @@ public final class IteratorBatchWorker {
static final String TASK_QUEUE = "IteratorBatch";
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker(TASK_QUEUE);
diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java
index f4d689f4a..e3a6b062d 100644
--- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java
+++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java
@@ -4,14 +4,26 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
public class SlidingWindowBatchStarter {
@SuppressWarnings("CatchAndPrintStackTrace")
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient workflowClient = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient workflowClient =
+ WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build();
BatchWorkflow batchWorkflow = workflowClient.newWorkflowStub(BatchWorkflow.class, options);
WorkflowClient.start(batchWorkflow::processBatch, 10, 25, 3);
diff --git a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java
index 32dd8e09c..20caa5ead 100644
--- a/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java
+++ b/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java
@@ -1,9 +1,11 @@
package io.temporal.samples.batch.slidingwindow;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
/** Hosts sliding window batch sample workflow and activity implementations. */
public final class SlidingWindowBatchWorker {
@@ -11,8 +13,17 @@ public final class SlidingWindowBatchWorker {
static final String TASK_QUEUE = "SlidingWindow";
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker(TASK_QUEUE);
diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java
index b791065da..cb7d1e594 100644
--- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java
+++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java
@@ -3,17 +3,28 @@
import com.google.common.base.Throwables;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
public class TripBookingClient {
static final String TASK_QUEUE = "TripBooking";
public static void main(String[] args) {
- // gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // gRPC stubs wrapper that talks to the temporal service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkflowOptions options =
WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId("Booking1").build();
diff --git a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java
index b538e0942..6c0fb87b2 100644
--- a/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java
+++ b/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorker.java
@@ -1,18 +1,29 @@
package io.temporal.samples.bookingsaga;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class TripBookingWorker {
@SuppressWarnings("CatchAndPrintStackTrace")
public static void main(String[] args) {
- // gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // gRPC stubs wrapper that talks to the temporal service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// worker factory that can be used to create workers for specific task queues
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java
index cebbc93b8..74aa32b86 100644
--- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java
+++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingClient.java
@@ -3,17 +3,28 @@
import com.google.common.base.Throwables;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
public class TripBookingClient {
static final String TASK_QUEUE = "TripBookingSync";
public static void main(String[] args) {
- // gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // gRPC stubs wrapper that talks to the temporal service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkflowOptions options =
WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId("Booking1").build();
diff --git a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java
index 151bd62ae..c70dc9481 100644
--- a/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java
+++ b/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorker.java
@@ -1,18 +1,29 @@
package io.temporal.samples.bookingsyncsaga;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class TripBookingWorker {
@SuppressWarnings("CatchAndPrintStackTrace")
public static void main(String[] args) {
// gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// worker factory that can be used to create workers for specific task queues
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java b/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java
index 9be315a8a..9f9cbe797 100644
--- a/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java
+++ b/core/src/main/java/io/temporal/samples/common/QueryWorkflowExecution.java
@@ -3,7 +3,9 @@
import io.temporal.api.common.v1.WorkflowExecution;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
import java.util.Optional;
/**
@@ -27,9 +29,18 @@ public static void main(String[] args) {
String runId = args.length == 3 ? args[2] : "";
// gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkflowExecution workflowExecution =
WorkflowExecution.newBuilder().setWorkflowId(workflowId).setRunId(runId).build();
diff --git a/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java b/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java
index bf8ddd793..30c73c14f 100644
--- a/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java
+++ b/core/src/main/java/io/temporal/samples/countinterceptor/InterceptorStarter.java
@@ -5,6 +5,7 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
import io.temporal.common.interceptors.WorkflowClientInterceptor;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.countinterceptor.activities.MyActivitiesImpl;
import io.temporal.samples.countinterceptor.workflow.MyChildWorkflowImpl;
import io.temporal.samples.countinterceptor.workflow.MyWorkflow;
@@ -13,6 +14,7 @@
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.worker.WorkerFactoryOptions;
+import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,7 +31,16 @@ public static void main(String[] args) {
final ClientCounter clientCounter = new ClientCounter();
final WorkflowClientInterceptor clientInterceptor = new SimpleClientInterceptor(clientCounter);
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
WorkflowClient client =
WorkflowClient.newInstance(
service, WorkflowClientOptions.newBuilder().setInterceptors(clientInterceptor).build());
diff --git a/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypes.java b/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypes.java
new file mode 100644
index 000000000..a97ebd26c
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypes.java
@@ -0,0 +1,18 @@
+package io.temporal.samples.customannotation;
+
+import java.lang.annotation.*;
+
+/**
+ * BenignExceptionTypes is an annotation that can be used to specify an exception type is benign and
+ * not an issue worth logging.
+ *
+ *
For this annotation to work, {@link BenignExceptionTypesAnnotationInterceptor} must be passed
+ * as a worker interceptor to the worker factory.
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface BenignExceptionTypes {
+ /** Type of exceptions that should be considered benign and not logged as errors. */
+ Class extends Exception>[] value();
+}
diff --git a/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypesAnnotationInterceptor.java b/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypesAnnotationInterceptor.java
new file mode 100644
index 000000000..71ee51a9d
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/customannotation/BenignExceptionTypesAnnotationInterceptor.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.customannotation;
+
+import io.temporal.activity.ActivityExecutionContext;
+import io.temporal.common.interceptors.ActivityInboundCallsInterceptor;
+import io.temporal.common.interceptors.WorkerInterceptorBase;
+import io.temporal.common.metadata.POJOActivityImplMetadata;
+import io.temporal.common.metadata.POJOActivityMethodMetadata;
+import io.temporal.failure.ApplicationErrorCategory;
+import io.temporal.failure.ApplicationFailure;
+import io.temporal.failure.TemporalFailure;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Checks if the activity method has the {@link BenignExceptionTypes} annotation. If it does, it
+ * will throw an ApplicationFailure with {@link ApplicationErrorCategory#BENIGN}.
+ */
+public class BenignExceptionTypesAnnotationInterceptor extends WorkerInterceptorBase {
+
+ @Override
+ public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) {
+ return new ActivityInboundCallsInterceptorAnnotation(next);
+ }
+
+ public static class ActivityInboundCallsInterceptorAnnotation
+ extends io.temporal.common.interceptors.ActivityInboundCallsInterceptorBase {
+ private final ActivityInboundCallsInterceptor next;
+ private Set> benignExceptionTypes = new HashSet<>();
+
+ public ActivityInboundCallsInterceptorAnnotation(ActivityInboundCallsInterceptor next) {
+ super(next);
+ this.next = next;
+ }
+
+ @Override
+ public void init(ActivityExecutionContext context) {
+ List activityMethods =
+ POJOActivityImplMetadata.newInstance(context.getInstance().getClass())
+ .getActivityMethods();
+ POJOActivityMethodMetadata currentActivityMethod =
+ activityMethods.stream()
+ .filter(x -> x.getActivityTypeName().equals(context.getInfo().getActivityType()))
+ .findFirst()
+ .get();
+ // Get the implementation method from the interface method
+ Method implementationMethod;
+ try {
+ implementationMethod =
+ context
+ .getInstance()
+ .getClass()
+ .getMethod(
+ currentActivityMethod.getMethod().getName(),
+ currentActivityMethod.getMethod().getParameterTypes());
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ // Get the @BenignExceptionTypes annotations from the implementation method
+ BenignExceptionTypes an = implementationMethod.getAnnotation(BenignExceptionTypes.class);
+ if (an != null && an.value() != null) {
+ benignExceptionTypes = new HashSet<>(Arrays.asList(an.value()));
+ }
+ next.init(context);
+ }
+
+ @Override
+ public ActivityOutput execute(ActivityInput input) {
+ if (benignExceptionTypes.isEmpty()) {
+ return next.execute(input);
+ }
+ try {
+ return next.execute(input);
+ } catch (TemporalFailure tf) {
+ throw tf;
+ } catch (Exception e) {
+ if (benignExceptionTypes.contains(e.getClass())) {
+ // If the exception is in the list of benign exceptions, throw an ApplicationFailure
+ // with a BENIGN category
+ throw ApplicationFailure.newBuilder()
+ .setMessage(e.getMessage())
+ .setType(e.getClass().getName())
+ .setCause(e)
+ .setCategory(ApplicationErrorCategory.BENIGN)
+ .build();
+ }
+ // If the exception is not in the list of benign exceptions, rethrow it
+ throw e;
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java b/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java
new file mode 100644
index 000000000..db6df4229
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/customannotation/CustomAnnotation.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
+ *
+ * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Modifications copyright (C) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not
+ * use this file except in compliance with the License. A copy of the License is
+ * located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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.temporal.samples.customannotation;
+
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityMethod;
+import io.temporal.activity.ActivityOptions;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerFactory;
+import io.temporal.worker.WorkerFactoryOptions;
+import io.temporal.workflow.Workflow;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
+import java.time.Duration;
+
+public class CustomAnnotation {
+
+ // Define the task queue name
+ static final String TASK_QUEUE = "CustomAnnotationTaskQueue";
+
+ // Define our workflow unique id
+ static final String WORKFLOW_ID = "CustomAnnotationWorkflow";
+
+ /**
+ * The Workflow Definition's Interface must contain one method annotated with @WorkflowMethod.
+ *
+ * Workflow Definitions should not contain any heavyweight computations, non-deterministic
+ * code, network calls, database operations, etc. Those things should be handled by the
+ * Activities.
+ *
+ * @see WorkflowInterface
+ * @see WorkflowMethod
+ */
+ @WorkflowInterface
+ public interface GreetingWorkflow {
+
+ /**
+ * This is the method that is executed when the Workflow Execution is started. The Workflow
+ * Execution completes when this method finishes execution.
+ */
+ @WorkflowMethod
+ String getGreeting(String name);
+ }
+
+ /**
+ * This is the Activity Definition's Interface. Activities are building blocks of any Temporal
+ * Workflow and contain any business logic that could perform long running computation, network
+ * calls, etc.
+ *
+ *
Annotating Activity Definition methods with @ActivityMethod is optional.
+ *
+ * @see ActivityInterface
+ * @see ActivityMethod
+ */
+ @ActivityInterface
+ public interface GreetingActivities {
+
+ /** Define your activity method which can be called during workflow execution */
+ String composeGreeting(String greeting, String name);
+ }
+
+ // Define the workflow implementation which implements our getGreeting workflow method.
+ public static class GreetingWorkflowImpl implements GreetingWorkflow {
+
+ /**
+ * Define the GreetingActivities stub. Activity stubs are proxies for activity invocations that
+ * are executed outside of the workflow thread on the activity worker, that can be on a
+ * different host. Temporal is going to dispatch the activity results back to the workflow and
+ * unblock the stub as soon as activity is completed on the activity worker.
+ */
+ private final GreetingActivities activities =
+ Workflow.newActivityStub(
+ GreetingActivities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build());
+
+ @Override
+ public String getGreeting(String name) {
+ // This is a blocking call that returns only after activity is completed.
+ return activities.composeGreeting("Hello", name);
+ }
+ }
+
+ /**
+ * Implementation of our workflow activity interface. It overwrites our defined composeGreeting
+ * activity method.
+ */
+ static class GreetingActivitiesImpl implements GreetingActivities {
+ private int callCount;
+
+ /**
+ * Our activity implementation simulates a failure 3 times. Given our previously set
+ * RetryOptions, our workflow is going to retry our activity execution.
+ */
+ @Override
+ @BenignExceptionTypes({IllegalStateException.class})
+ public synchronized String composeGreeting(String greeting, String name) {
+ if (++callCount < 4) {
+ System.out.println("composeGreeting activity is going to fail");
+ throw new IllegalStateException("not yet");
+ }
+
+ // after 3 unsuccessful retries we finally can complete our activity execution
+ System.out.println("composeGreeting activity is going to complete");
+ return greeting + " " + name + "!";
+ }
+ }
+
+ /**
+ * With our Workflow and Activities defined, we can now start execution. The main method starts
+ * the worker and then the workflow.
+ */
+ public static void main(String[] args) {
+
+ // Get a Workflow service stub.
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+
+ /*
+ * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
+ */
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+
+ /*
+ * Define the workflow factory. It is used to create workflow workers for a specific task queue.
+ */
+ WorkerFactory factory =
+ WorkerFactory.newInstance(
+ client,
+ WorkerFactoryOptions.newBuilder()
+ .setWorkerInterceptors(new BenignExceptionTypesAnnotationInterceptor())
+ .build());
+
+ /*
+ * Define the workflow worker. Workflow workers listen to a defined task queue and process
+ * workflows and activities.
+ */
+ Worker worker = factory.newWorker(TASK_QUEUE);
+
+ /*
+ * Register our workflow implementation with the worker.
+ * Workflow implementations must be known to the worker at runtime in
+ * order to dispatch workflow tasks.
+ */
+ worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class);
+
+ /*
+ * Register our Activity Types with the Worker. Since Activities are stateless and thread-safe,
+ * the Activity Type is a shared instance.
+ */
+ worker.registerActivitiesImplementations(new GreetingActivitiesImpl());
+
+ /*
+ * Start all the workers registered for a specific task queue.
+ * The started workers then start polling for workflows and activities.
+ */
+ factory.start();
+
+ // Set our workflow options
+ WorkflowOptions workflowOptions =
+ WorkflowOptions.newBuilder().setWorkflowId(WORKFLOW_ID).setTaskQueue(TASK_QUEUE).build();
+
+ // Create the workflow client stub. It is used to start our workflow execution.
+ GreetingWorkflow workflow = client.newWorkflowStub(GreetingWorkflow.class, workflowOptions);
+
+ /*
+ * Execute our workflow and wait for it to complete. The call to our getGreeting method is
+ * synchronous.
+ *
+ * See {@link io.temporal.samples.hello.HelloSignal} for an example of starting workflow
+ * without waiting synchronously for its result.
+ */
+ String greeting = workflow.getGreeting("World");
+
+ // Display workflow execution results
+ System.out.println(greeting);
+ System.exit(0);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/customannotation/README.md b/core/src/main/java/io/temporal/samples/customannotation/README.md
new file mode 100644
index 000000000..f04b25915
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/customannotation/README.md
@@ -0,0 +1,9 @@
+# Custom annotation
+
+The sample demonstrates how to create a custom annotation using an interceptor. In this case the annotation allows specifying an exception of a certain type is benign.
+
+This samples shows a custom annotation on an activity method, but the same approach can be used for workflow methods or Nexus operations.
+
+```bash
+./gradlew -q execute -PmainClass=io.temporal.samples.customannotation.CustomAnnotation
+```
diff --git a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java
index 82921b8dc..3bd8497b7 100644
--- a/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java
+++ b/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionStarter.java
@@ -8,22 +8,33 @@
import io.temporal.client.WorkflowServiceException;
import io.temporal.common.SearchAttributeKey;
import io.temporal.common.SearchAttributes;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.OperatorServiceStubs;
import io.temporal.serviceclient.OperatorServiceStubsOptions;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import java.util.Collections;
public class CustomChangeVersionStarter {
private static SearchAttributeKey CUSTOM_CHANGE_VERSION =
SearchAttributeKey.forKeyword("CustomChangeVersion");
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
private static final String taskQueue = "customChangeVersionTaskQueue";
private static final String workflowId = "CustomChangeVersionWorkflow";
public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory workerFactory = WorkerFactory.newInstance(client);
Worker worker = workerFactory.newWorker(taskQueue);
diff --git a/core/src/main/java/io/temporal/samples/dsl/Starter.java b/core/src/main/java/io/temporal/samples/dsl/Starter.java
index e0336d659..257531048 100644
--- a/core/src/main/java/io/temporal/samples/dsl/Starter.java
+++ b/core/src/main/java/io/temporal/samples/dsl/Starter.java
@@ -3,22 +3,29 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.dsl.model.Flow;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class Starter {
- public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- public static final WorkflowClient client = WorkflowClient.newInstance(service);
- public static final WorkerFactory factory = WorkerFactory.newInstance(client);
-
public static void main(String[] args) {
Flow flow = getFlowFromResource();
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker("dsl-task-queue");
worker.registerWorkflowImplementationTypes(DslWorkflowImpl.class);
diff --git a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java
index 623efa310..3abd20a7c 100644
--- a/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java
+++ b/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnClient.java
@@ -2,7 +2,9 @@
import io.temporal.api.enums.v1.WorkflowIdConflictPolicy;
import io.temporal.client.*;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
public class EarlyReturnClient {
private static final String TASK_QUEUE = "EarlyReturnTaskQueue";
@@ -15,8 +17,17 @@ public static void main(String[] args) {
// Set up the WorkflowClient
public static WorkflowClient setupWorkflowClient() {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- return WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ return WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
}
// Run workflow using 'updateWithStart'
diff --git a/core/src/main/java/io/temporal/samples/encodefailures/Starter.java b/core/src/main/java/io/temporal/samples/encodefailures/Starter.java
index 9e4e17fe0..f08766881 100644
--- a/core/src/main/java/io/temporal/samples/encodefailures/Starter.java
+++ b/core/src/main/java/io/temporal/samples/encodefailures/Starter.java
@@ -8,10 +8,12 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.common.converter.CodecDataConverter;
import io.temporal.common.converter.DefaultDataConverter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.worker.WorkflowImplementationOptions;
+import java.io.IOException;
import java.util.Collections;
public class Starter {
@@ -19,7 +21,16 @@ public class Starter {
private static final String WORKFLOW_ID = "CustomerValidationWorkflow";
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// CodecDataConverter defines our data converter and codec
// sets encodeFailureAttributes to true
diff --git a/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java b/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java
index 00636fb29..83f10d95c 100644
--- a/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java
+++ b/core/src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java
@@ -8,12 +8,14 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.common.converter.CodecDataConverter;
import io.temporal.common.converter.DefaultDataConverter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.util.Collections;
@@ -68,7 +70,16 @@ public String composeGreeting(String greeting, String name) {
public static void main(String[] args) {
// gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
WorkflowClient client =
WorkflowClient.newInstance(
diff --git a/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java b/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java
new file mode 100644
index 000000000..cee9df5a5
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/envconfig/LoadFromFile.java
@@ -0,0 +1,81 @@
+package io.temporal.samples.envconfig;
+
+// @@@SNIPSTART java-env-config-profile
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowClientOptions;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.envconfig.LoadClientConfigProfileOptions;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.serviceclient.WorkflowServiceStubsOptions;
+import java.nio.file.Paths;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This sample demonstrates loading the default environment configuration profile from a TOML file.
+ */
+public class LoadFromFile {
+
+ private static final Logger logger = LoggerFactory.getLogger(LoadFromFile.class);
+
+ public static void main(String[] args) {
+ try {
+ // For this sample to be self-contained, we explicitly provide the path to
+ // the config.toml file included in this directory.
+ // By default though, the config.toml file will be loaded from
+ // ~/.config/temporal/temporal.toml (or the equivalent standard config directory on your OS).
+ String configFilePath =
+ Paths.get(LoadFromFile.class.getResource("/config.toml").toURI()).toString();
+
+ logger.info("--- Loading 'default' profile from {} ---", configFilePath);
+
+ // Load client profile from file. By default, this loads the "default" profile
+ // and applies any environment variable overrides.
+ ClientConfigProfile profile =
+ ClientConfigProfile.load(
+ LoadClientConfigProfileOptions.newBuilder()
+ .setConfigFilePath(configFilePath)
+ .build());
+
+ // Convert profile to client options (equivalent to Python's load_client_connect_config)
+ WorkflowServiceStubsOptions serviceStubsOptions = profile.toWorkflowServiceStubsOptions();
+ WorkflowClientOptions clientOptions = profile.toWorkflowClientOptions();
+
+ logger.info("Loaded 'default' profile from {}", configFilePath);
+ logger.info(" Address: {}", serviceStubsOptions.getTarget());
+ logger.info(" Namespace: {}", clientOptions.getNamespace());
+ if (serviceStubsOptions.getHeaders() != null
+ && !serviceStubsOptions.getHeaders().keys().isEmpty()) {
+ logger.info(" gRPC Metadata keys: {}", serviceStubsOptions.getHeaders().keys());
+ }
+
+ logger.info("\nAttempting to connect to client...");
+
+ try {
+ // Create the workflow client using the loaded configuration
+ WorkflowClient client =
+ WorkflowClient.newInstance(
+ WorkflowServiceStubs.newServiceStubs(serviceStubsOptions), clientOptions);
+
+ // Test the connection by getting system info
+ var systemInfo =
+ client
+ .getWorkflowServiceStubs()
+ .blockingStub()
+ .getSystemInfo(
+ io.temporal.api.workflowservice.v1.GetSystemInfoRequest.getDefaultInstance());
+
+ logger.info("✅ Client connected successfully!");
+ logger.info(" Server version: {}", systemInfo.getServerVersion());
+
+ } catch (Exception e) {
+ logger.error("❌ Failed to connect: {}", e.getMessage());
+ }
+
+ } catch (Exception e) {
+ logger.error("Failed to load configuration: {}", e.getMessage(), e);
+ System.exit(1);
+ }
+ }
+}
+// @@@SNIPEND
diff --git a/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java b/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java
new file mode 100644
index 000000000..20270e1f0
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/envconfig/LoadProfile.java
@@ -0,0 +1,89 @@
+package io.temporal.samples.envconfig;
+
+// @@@SNIPSTART java-env-config-profile-with-overrides
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowClientOptions;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.envconfig.LoadClientConfigProfileOptions;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.serviceclient.WorkflowServiceStubsOptions;
+import java.nio.file.Paths;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This sample demonstrates loading a specific profile from a TOML configuration file with
+ * programmatic overrides.
+ */
+public class LoadProfile {
+
+ private static final Logger logger = LoggerFactory.getLogger(LoadProfile.class);
+
+ public static void main(String[] args) {
+ String profileName = "staging";
+
+ try {
+ // For this sample to be self-contained, we explicitly provide the path to
+ // the config.toml file included in this directory.
+ String configFilePath =
+ Paths.get(LoadProfile.class.getResource("/config.toml").toURI()).toString();
+
+ logger.info("--- Loading '{}' profile from {} ---", profileName, configFilePath);
+
+ // Load specific profile from file with environment variable overrides
+ ClientConfigProfile profile =
+ ClientConfigProfile.load(
+ LoadClientConfigProfileOptions.newBuilder()
+ .setConfigFilePath(configFilePath)
+ .setConfigFileProfile(profileName)
+ .build());
+
+ // Demonstrate programmatic override - fix the incorrect address from staging profile
+ logger.info("\n--- Applying programmatic override ---");
+ ClientConfigProfile.Builder profileBuilder = profile.toBuilder();
+ profileBuilder.setAddress("localhost:7233"); // Override the incorrect address
+ profile = profileBuilder.build();
+ logger.info(" Overridden address to: {}", profile.getAddress());
+
+ // Convert profile to client options (equivalent to Python's load_client_connect_config)
+ WorkflowServiceStubsOptions serviceStubsOptions = profile.toWorkflowServiceStubsOptions();
+ WorkflowClientOptions clientOptions = profile.toWorkflowClientOptions();
+
+ logger.info("Loaded '{}' profile from {}", profileName, configFilePath);
+ logger.info(" Address: {}", serviceStubsOptions.getTarget());
+ logger.info(" Namespace: {}", clientOptions.getNamespace());
+ if (serviceStubsOptions.getHeaders() != null
+ && !serviceStubsOptions.getHeaders().keys().isEmpty()) {
+ logger.info(" gRPC Metadata keys: {}", serviceStubsOptions.getHeaders().keys());
+ }
+
+ logger.info("\nAttempting to connect to client...");
+
+ try {
+ // Create the workflow client using the loaded configuration
+ WorkflowClient client =
+ WorkflowClient.newInstance(
+ WorkflowServiceStubs.newServiceStubs(serviceStubsOptions), clientOptions);
+
+ // Test the connection by getting system info
+ var systemInfo =
+ client
+ .getWorkflowServiceStubs()
+ .blockingStub()
+ .getSystemInfo(
+ io.temporal.api.workflowservice.v1.GetSystemInfoRequest.getDefaultInstance());
+
+ logger.info("✅ Client connected successfully!");
+ logger.info(" Server version: {}", systemInfo.getServerVersion());
+
+ } catch (Exception e) {
+ logger.error("❌ Failed to connect: {}", e.getMessage());
+ }
+
+ } catch (Exception e) {
+ logger.error("Failed to load configuration: {}", e.getMessage(), e);
+ System.exit(1);
+ }
+ }
+}
+// @@@SNIPEND
diff --git a/core/src/main/java/io/temporal/samples/envconfig/README.md b/core/src/main/java/io/temporal/samples/envconfig/README.md
new file mode 100644
index 000000000..0cb5df5c1
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/envconfig/README.md
@@ -0,0 +1,18 @@
+# Environment Configuration Sample
+
+This sample demonstrates how to configure a Temporal client using TOML configuration files. This allows you to manage connection settings across different environments without hardcoding them.
+
+The `config.toml` file defines three profiles:
+- `[profile.default]`: Local development configuration
+- `[profile.staging]`: Configuration with incorrect address to demonstrate overrides
+- `[profile.prod]`: Example production configuration (not runnable)
+
+**Load from file (default profile):**
+```bash
+./gradlew -q execute -PmainClass=io.temporal.samples.envconfig.LoadFromFile
+```
+
+**Load specific profile with overrides:**
+```bash
+./gradlew -q execute -PmainClass=io.temporal.samples.envconfig.LoadProfile
+```
\ No newline at end of file
diff --git a/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java b/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java
index b4bd1e825..4efe7d1f6 100644
--- a/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java
+++ b/core/src/main/java/io/temporal/samples/excludefrominterceptor/RunMyWorkflows.java
@@ -3,6 +3,7 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.excludefrominterceptor.activities.ForInterceptorActivitiesImpl;
import io.temporal.samples.excludefrominterceptor.activities.MyActivitiesImpl;
import io.temporal.samples.excludefrominterceptor.interceptor.MyWorkerInterceptor;
@@ -11,13 +12,23 @@
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.worker.WorkerFactoryOptions;
+import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
public class RunMyWorkflows {
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactoryOptions wfo =
WorkerFactoryOptions.newBuilder()
diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java
index f2c1ee95a..5020bf519 100644
--- a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java
+++ b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingStarter.java
@@ -4,17 +4,28 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
import java.net.URL;
/** Starts a file processing sample workflow. */
public class FileProcessingStarter {
public static void main(String[] args) throws Exception {
- // gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // gRPC stubs wrapper that talks to the temporal service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
FileProcessingWorkflow workflow =
client.newWorkflowStub(
FileProcessingWorkflow.class,
diff --git a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java
index b154a2c23..711ca7343 100644
--- a/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java
+++ b/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorker.java
@@ -1,9 +1,11 @@
package io.temporal.samples.fileprocessing;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import java.lang.management.ManagementFactory;
/**
@@ -21,10 +23,19 @@ public static void main(String[] args) {
String hostSpecifiTaskQueue = ManagementFactory.getRuntimeMXBean().getName();
- // gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // gRPC stubs wrapper that talks to the temporal service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// worker factory that can be used to create workers for specific task queues
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java b/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java
index d9bb276be..4a91026f8 100644
--- a/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java
+++ b/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java
@@ -1,13 +1,30 @@
package io.temporal.samples.getresultsasync;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class Worker {
- public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- public static final WorkflowClient client = WorkflowClient.newInstance(service);
- public static final WorkerFactory factory = WorkerFactory.newInstance(client);
+ public static final WorkflowServiceStubs service;
+ public static final WorkflowClient client;
+ public static final WorkerFactory factory;
+
+ static {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ factory = WorkerFactory.newInstance(client);
+ }
+
public static final String TASK_QUEUE_NAME = "asyncstartqueue";
public static void main(String[] args) {
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java b/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java
index 38ea8f097..2f8d67457 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloAccumulator.java
@@ -11,6 +11,7 @@
import io.temporal.client.WorkflowNotFoundException;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -18,6 +19,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.io.Serializable;
import java.time.Duration;
import java.util.ArrayDeque;
@@ -293,14 +295,17 @@ public void exit() {
*/
public static void main(String[] args) throws Exception {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query
- * Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
client.getWorkflowServiceStubs().healthCheck();
/*
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java
index 3c890d3ab..9b202e0c2 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloActivity.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloActivity.java
@@ -5,12 +5,14 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -105,13 +107,22 @@ public String composeGreeting(String greeting, String name) {
*/
public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
// Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
/*
* Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
*/
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java
index 1da873e2c..3f2309993 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloActivityExclusiveChoice.java
@@ -4,12 +4,14 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@@ -165,12 +167,21 @@ public static void main(String[] args) {
* Define the workflow service. It is a gRPC stubs wrapper which talks to the docker instance of
* our locally running Temporal service.
*/
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
/*
* Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
*/
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java
index f7f01b3a3..4f78cfa2f 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java
@@ -5,12 +5,14 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.common.RetryOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/** Sample Temporal workflow that demonstrates workflow activity retries. */
@@ -140,13 +142,17 @@ public synchronized String composeGreeting(String greeting, String name) {
*/
public static void main(String[] args) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsync.java b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java
index 7b068f7bf..25e8c3c5f 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloAsync.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloAsync.java
@@ -4,6 +4,7 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -12,6 +13,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/** Sample Temporal Workflow Definition that demonstrates an asynchronous Activity Execution. */
@@ -110,13 +112,18 @@ public String composeGreeting(String greeting, String name) {
*/
public static void main(String[] args) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java
index 87f9cbee7..f52072738 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java
@@ -4,12 +4,14 @@
import io.temporal.client.ActivityCompletionClient;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -143,14 +145,18 @@ private void composeGreetingAsync(byte[] taskToken, String greeting, String name
*/
public static void main(String[] args) throws ExecutionException, InterruptedException {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow
- * Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java
index 4da2b6ee1..6b68d85cb 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java
@@ -4,6 +4,7 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -12,6 +13,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/** Sample Temporal Workflow Definition that demonstrates an asynchronous Activity Executions. */
@@ -128,13 +130,18 @@ public String composeGreeting(String greeting, String name) {
*/
public static void main(String[] args) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloAwait.java b/core/src/main/java/io/temporal/samples/hello/HelloAwait.java
index 069f5bb65..588b9e3fc 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloAwait.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloAwait.java
@@ -3,6 +3,7 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.failure.ApplicationFailure;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
@@ -11,6 +12,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/**
@@ -80,13 +82,18 @@ public void waitForName(String name) {
*/
public static void main(String[] args) throws Exception {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Await, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java
index 59cc0c7c8..c98a6fac5 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java
@@ -8,6 +8,7 @@
import io.temporal.client.ActivityCompletionException;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.failure.ActivityFailure;
import io.temporal.failure.CanceledFailure;
import io.temporal.serviceclient.WorkflowServiceStubs;
@@ -20,6 +21,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -231,13 +233,18 @@ private void sleep(int seconds) {
*/
public static void main(String[] args) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java
index 6efb24b0a..5961b6833 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloCancellationScopeWithTimer.java
@@ -4,12 +4,14 @@
import io.temporal.client.ActivityCompletionException;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.failure.ActivityFailure;
import io.temporal.failure.CanceledFailure;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.*;
+import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
@@ -153,12 +155,21 @@ private void sleep(int seconds) {
public static void main(String[] args) {
// Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
/*
* Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
*/
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloChild.java b/core/src/main/java/io/temporal/samples/hello/HelloChild.java
index f631f5cbe..4c4c37276 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloChild.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloChild.java
@@ -2,6 +2,7 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -10,6 +11,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
/**
* Sample Temporal Workflow Definition that demonstrates the execution of a Child Workflow. Child
@@ -105,13 +107,18 @@ public String composeGreeting(String greeting, String name) {
*/
public static void main(String[] args) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the worker factory. It is used to create workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloCron.java b/core/src/main/java/io/temporal/samples/hello/HelloCron.java
index 1d46d1c33..dafbfe11e 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloCron.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloCron.java
@@ -7,12 +7,14 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowExecutionAlreadyStarted;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/**
@@ -108,13 +110,18 @@ public void greet(String greeting) {
*/
public static void main(String[] args) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java b/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java
index 13d3d9041..a407e64d6 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloDelayedStart.java
@@ -3,12 +3,14 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.common.WorkflowExecutionHistory;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/** Sample Temporal Workflow Definition that shows how to use delayed start. */
@@ -50,13 +52,18 @@ public void start() {
}
public static void main(String[] args) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java
index 8baaf2364..a40087894 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloDetachedCancellationScope.java
@@ -8,11 +8,13 @@
import io.temporal.client.WorkflowFailedException;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.failure.ActivityFailure;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.*;
+import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -132,13 +134,22 @@ public String queryGreeting() {
public static void main(String[] args) throws InterruptedException {
// Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
/*
* Get a Workflow service client which can be used to start, Signal, and Query Workflow
* Executions.
*/
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java
index f770f4263..f779bdfc3 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloDynamic.java
@@ -7,6 +7,7 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
import io.temporal.common.converter.EncodedValues;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -14,6 +15,7 @@
import io.temporal.workflow.DynamicSignalHandler;
import io.temporal.workflow.DynamicWorkflow;
import io.temporal.workflow.Workflow;
+import java.io.IOException;
import java.time.Duration;
public class HelloDynamic {
@@ -71,14 +73,18 @@ public Object execute(EncodedValues args) {
*/
public static void main(String[] arg) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow
- * Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java b/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java
index feb0d45f1..4e1a3b533 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java
@@ -5,12 +5,14 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -110,13 +112,18 @@ public String composeGreeting(String greeting, String name) {
*/
public static void main(String[] args) {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloException.java b/core/src/main/java/io/temporal/samples/hello/HelloException.java
index 8c1daaccb..6b0788043 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloException.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloException.java
@@ -8,6 +8,7 @@
import io.temporal.client.WorkflowException;
import io.temporal.client.WorkflowOptions;
import io.temporal.common.RetryOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -153,13 +154,18 @@ public String composeGreeting(String greeting, String name) {
*/
public static void main(String[] args) {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java
index 9436eab6b..c82a76e06 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloLocalActivity.java
@@ -5,12 +5,14 @@
import io.temporal.activity.LocalActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/**
@@ -90,10 +92,19 @@ public String composeGreeting(String greeting, String name) {
}
public static void main(String[] args) {
- // gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // gRPC stubs wrapper that talks to the temporal service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// worker factory that can be used to create workers for specific task queues
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java
index ab3e7c789..21b716070 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloParallelActivity.java
@@ -4,10 +4,12 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.*;
+import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
@@ -116,13 +118,18 @@ public List getGreetings(List names) {
*/
public static void main(String[] args) {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java b/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java
index 418244684..f26370f21 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloPeriodic.java
@@ -7,6 +7,7 @@
import io.temporal.client.WorkflowExecutionAlreadyStarted;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -14,6 +15,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.util.Random;
@@ -183,13 +185,18 @@ public void greet(String greeting) {
"CatchAndPrintStackTrace") // in this simple example advanced error logging is not required
public static void main(String[] args) throws InterruptedException {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java b/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java
index a6bb70f1f..71a2c3ffd 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java
@@ -4,12 +4,14 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/**
@@ -150,13 +152,18 @@ public String composeGreeting(String name) {
*/
public static void main(String[] args) {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloQuery.java b/core/src/main/java/io/temporal/samples/hello/HelloQuery.java
index 012ae1b97..e89f83f07 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloQuery.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloQuery.java
@@ -2,6 +2,7 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -9,6 +10,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/** Sample Temporal Workflow Definition that demonstrates how to Query a Workflow. */
@@ -78,13 +80,18 @@ public String queryGreeting() {
*/
public static void main(String[] args) throws InterruptedException {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSaga.java b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java
index 5dfc0848b..4fb3bc6a1 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloSaga.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloSaga.java
@@ -5,6 +5,7 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -14,6 +15,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
/**
@@ -258,13 +260,18 @@ public void execute() {
*/
public static void main(String[] args) {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java b/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java
index 7d3c5ef1a..698f4f83b 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloSchedules.java
@@ -9,12 +9,14 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.client.schedules.*;
import io.temporal.common.converter.GlobalDataConverter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
@@ -130,13 +132,18 @@ public void greet(String greeting) {
*/
public static void main(String[] args) throws InterruptedException {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java
index e2b1c0f9c..7115ebaa5 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java
@@ -12,12 +12,14 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.common.converter.DataConverter;
import io.temporal.common.converter.GlobalDataConverter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@@ -113,13 +115,18 @@ public String composeGreeting(String greeting, String name) {
*/
public static void main(String[] args) {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java
index e0c39bf91..f894dc343 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloSideEffect.java
@@ -4,6 +4,7 @@
import io.temporal.activity.ActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -11,6 +12,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.security.SecureRandom;
import java.time.Duration;
import java.util.Random;
@@ -159,14 +161,18 @@ public String sayGoodBye(String greeting) {
*/
public static void main(String[] args) {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow
- * Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignal.java b/core/src/main/java/io/temporal/samples/hello/HelloSignal.java
index cd5a488ab..e2e50fc85 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloSignal.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloSignal.java
@@ -2,6 +2,7 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -9,6 +10,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -94,13 +96,18 @@ public void exit() {
*/
public static void main(String[] args) throws Exception {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java
new file mode 100644
index 000000000..f579388ae
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java
@@ -0,0 +1,219 @@
+package io.temporal.samples.hello;
+
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityOptions;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowFailedException;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerFactory;
+import io.temporal.worker.WorkflowImplementationOptions;
+import io.temporal.workflow.*;
+import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Sample Temporal workflow that demonstrates how to use WorkflowInit with clients starting
+ * execution using SignalWithStart
+ */
+public class HelloSignalWithStartAndWorkflowInit {
+ static final String TASK_QUEUE = "HelloWithInitTaskQueue";
+
+ public interface MyWorkflow {
+ @WorkflowMethod
+ String greet(Person person);
+
+ @SignalMethod
+ void addGreeting(Person person);
+ }
+
+ @WorkflowInterface
+ public interface MyWorkflowWithInit extends MyWorkflow {}
+
+ @WorkflowInterface
+ public interface MyWorkflowNoInit extends MyWorkflow {}
+
+ public static class WithInitMyWorkflowImpl implements MyWorkflowWithInit {
+ // We dont initialize peopleToGreet on purpose
+ private List peopleToGreet;
+ private MyGreetingActivities activities =
+ Workflow.newActivityStub(
+ MyGreetingActivities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
+
+ @WorkflowInit
+ public WithInitMyWorkflowImpl(Person person) {
+ peopleToGreet = new ArrayList<>();
+ }
+
+ @Override
+ public String greet(Person person) {
+ peopleToGreet.add(person);
+ List greetings = new ArrayList<>();
+
+ while (!peopleToGreet.isEmpty()) {
+ // run activity...
+ greetings.add(activities.greet(peopleToGreet.get(0)));
+ peopleToGreet.remove(0);
+ }
+ return StringUtils.join(greetings, ",");
+ }
+
+ @Override
+ public void addGreeting(Person person) {
+ peopleToGreet.add(person);
+ }
+ }
+
+ public static class WithoutInitMyWorkflowImpl implements MyWorkflowNoInit {
+ // We dont initialize peopleToGreet on purpose
+ private List peopleToGreet;
+ private MyGreetingActivities activities =
+ Workflow.newActivityStub(
+ MyGreetingActivities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
+
+ @Override
+ public String greet(Person person) {
+ peopleToGreet.add(person);
+ List greetings = new ArrayList<>();
+
+ while (!peopleToGreet.isEmpty()) {
+ // run activity...
+ greetings.add(activities.greet(peopleToGreet.get(0)));
+ peopleToGreet.remove(0);
+ }
+ return StringUtils.join(greetings, ",");
+ }
+
+ @Override
+ public void addGreeting(Person person) {
+ peopleToGreet.add(person);
+ }
+ }
+
+ @ActivityInterface
+ public interface MyGreetingActivities {
+ public String greet(Person person);
+ }
+
+ public static class MyGreetingActivitiesImpl implements MyGreetingActivities {
+ @Override
+ public String greet(Person person) {
+ return "Hello " + person.firstName + " " + person.lastName;
+ }
+ }
+
+ public static class Person {
+ String firstName;
+ String lastName;
+ int age;
+
+ public Person() {}
+
+ public Person(String firstName, String lastName, int age) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.age = age;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+ }
+
+ public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+ Worker worker = factory.newWorker(TASK_QUEUE);
+
+ worker.registerWorkflowImplementationTypes(WithInitMyWorkflowImpl.class);
+ // We explicitly want to fail this workflow on NPE as thats what we expect without WorkflowInit
+ // As we didnt initialize peopleToGreet on purpose
+ worker.registerWorkflowImplementationTypes(
+ WorkflowImplementationOptions.newBuilder()
+ .setFailWorkflowExceptionTypes(NullPointerException.class)
+ .build(),
+ WithoutInitMyWorkflowImpl.class);
+ worker.registerActivitiesImplementations(new MyGreetingActivitiesImpl());
+
+ factory.start();
+
+ MyWorkflowWithInit withInitStub =
+ client.newWorkflowStub(
+ MyWorkflowWithInit.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId("with-init")
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+ // Start with init workflow which is expected to succeed
+ // As WorkflowInit will initialize peopleToGreet before signal handler is invoked
+ WorkflowStub.fromTyped(withInitStub)
+ .signalWithStart(
+ "addGreeting",
+ new Object[] {new Person("Michael", "Jordan", 55)},
+ new Object[] {new Person("John", "Stockton", 57)});
+
+ String result = WorkflowStub.fromTyped(withInitStub).getResult(String.class);
+ System.out.println("Result: " + result);
+
+ // Start without init, this execution is expected to fail as we set
+ // NullPointerException as a workflow failure type
+ // NPE is caused because we did not initialize peopleToGreet array
+ MyWorkflowNoInit noInitStub =
+ client.newWorkflowStub(
+ MyWorkflowNoInit.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId("without-init")
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+ WorkflowStub.fromTyped(noInitStub)
+ .signalWithStart(
+ "addGreeting",
+ new Object[] {new Person("Michael", "Jordan", 55)},
+ new Object[] {new Person("John", "Stockton", 57)});
+ try {
+ WorkflowStub.fromTyped(noInitStub).getResult(String.class);
+ } catch (WorkflowFailedException e) {
+ System.out.println("Expected workflow failure: " + e.getMessage());
+ }
+
+ System.exit(0);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java
index 26c22b2a2..ea2d29d2a 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloSignalWithTimer.java
@@ -5,11 +5,13 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.failure.CanceledFailure;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.*;
+import java.io.IOException;
import java.time.Duration;
import org.slf4j.Logger;
@@ -116,8 +118,17 @@ public void processValue(String value) {
}
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker(TASK_QUEUE);
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java
index f0dfb76c4..8629dfd62 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloTypedSearchAttributes.java
@@ -6,12 +6,14 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.common.SearchAttributeKey;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
@@ -149,13 +151,18 @@ public String composeGreeting(String greeting, List salutations, String
*/
public static void main(String[] args) {
- // Define the workflow service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Define the workflow service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java b/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java
index 329569738..6df8a8694 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloUpdate.java
@@ -6,6 +6,7 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
import io.temporal.client.WorkflowUpdateException;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.failure.ApplicationFailure;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
@@ -16,6 +17,7 @@
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
+import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -157,13 +159,18 @@ public void exit() {
*/
public static void main(String[] args) throws Exception {
- // Get a Workflow service stub.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
- /*
- * Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
- */
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Get a Workflow service stub.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
/*
* Define the workflow factory. It is used to create workflow workers for a specific task queue.
diff --git a/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java b/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java
index 94570db98..ec6f8a5ba 100644
--- a/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java
+++ b/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java
@@ -5,6 +5,7 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.failure.ActivityFailure;
import io.temporal.failure.CanceledFailure;
import io.temporal.failure.ChildWorkflowFailure;
@@ -12,6 +13,7 @@
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.*;
+import java.io.IOException;
import java.time.Duration;
/** Sample shows how to use workflow timer instead of WorkflowOptions->Run/ExecutionTimeout */
@@ -190,10 +192,19 @@ public String executeChild(String input) {
}
public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
// Create service stubs
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- // Crete workflow client
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ // Create workflow client
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// Create worker factory
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/hello/README.md b/core/src/main/java/io/temporal/samples/hello/README.md
index 41dd18271..c8ebbdb42 100644
--- a/core/src/main/java/io/temporal/samples/hello/README.md
+++ b/core/src/main/java/io/temporal/samples/hello/README.md
@@ -34,4 +34,5 @@ To run each hello world sample, use one of the following commands:
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSideEffect
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloUpdate
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignalWithTimer
+./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignalWithStartAndWorkflowInit
```
diff --git a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java
index f36f3176c..03392674c 100644
--- a/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java
+++ b/core/src/main/java/io/temporal/samples/keymanagementencryption/awsencryptionsdk/EncryptedPayloads.java
@@ -5,10 +5,12 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.common.converter.CodecDataConverter;
import io.temporal.common.converter.DefaultDataConverter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.hello.HelloActivity;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import java.util.Collections;
import software.amazon.cryptography.materialproviders.IKeyring;
import software.amazon.cryptography.materialproviders.MaterialProviders;
@@ -36,7 +38,16 @@ public static void main(String[] args) {
CreateAwsKmsMultiKeyringInput.builder().generator(generatorKey).build();
final IKeyring kmsKeyring = materialProviders.CreateAwsKmsMultiKeyring(keyringInput);
// gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
WorkflowClient client =
WorkflowClient.newInstance(
diff --git a/core/src/main/java/io/temporal/samples/listworkflows/Starter.java b/core/src/main/java/io/temporal/samples/listworkflows/Starter.java
index 1d9ef916c..ad7f62369 100644
--- a/core/src/main/java/io/temporal/samples/listworkflows/Starter.java
+++ b/core/src/main/java/io/temporal/samples/listworkflows/Starter.java
@@ -6,9 +6,11 @@
import io.temporal.api.workflowservice.v1.ListWorkflowExecutionsResponse;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -17,11 +19,23 @@
public class Starter {
public static final String TASK_QUEUE = "customerTaskQueue";
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
- private static final WorkerFactory factory = WorkerFactory.newInstance(client);
+ private static WorkflowServiceStubs service;
+ private static WorkflowClient client;
+ private static WorkerFactory factory;
public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ factory = WorkerFactory.newInstance(client);
+
// create some fake customers
List customers = new ArrayList<>();
customers.add(new Customer("c1", "John", "john@john.com", "new"));
diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java
index a213c3f81..ffe222899 100644
--- a/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java
+++ b/core/src/main/java/io/temporal/samples/metrics/MetricsStarter.java
@@ -9,9 +9,11 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.common.reporter.MicrometerClientStatsReporter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.metrics.workflow.MetricsWorkflow;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
+import java.io.IOException;
public class MetricsStarter {
public static void main(String[] args) {
@@ -35,12 +37,22 @@ public static void main(String[] args) {
// scrape endpoint.
Runtime.getRuntime().addShutdownHook(new Thread(() -> scrapeEndpoint.stop(1)));
- // Add metrics scope to workflow service stub options
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // Add metrics scope to workflow service stub options, preserving env config
WorkflowServiceStubsOptions stubOptions =
- WorkflowServiceStubsOptions.newBuilder().setMetricsScope(scope).build();
+ WorkflowServiceStubsOptions.newBuilder(profile.toWorkflowServiceStubsOptions())
+ .setMetricsScope(scope)
+ .build();
WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(stubOptions);
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkflowOptions workflowOptions =
WorkflowOptions.newBuilder()
diff --git a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java
index 4b5f3173f..9f95107cf 100644
--- a/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java
+++ b/core/src/main/java/io/temporal/samples/metrics/MetricsWorker.java
@@ -8,12 +8,14 @@
import io.micrometer.prometheus.PrometheusMeterRegistry;
import io.temporal.client.WorkflowClient;
import io.temporal.common.reporter.MicrometerClientStatsReporter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.metrics.activities.MetricsActivitiesImpl;
import io.temporal.samples.metrics.workflow.MetricsWorkflowImpl;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class MetricsWorker {
@@ -41,12 +43,22 @@ public static void main(String[] args) {
// Stopping the worker will stop the http server that exposes the
// scrape endpoint.
Runtime.getRuntime().addShutdownHook(new Thread(() -> scrapeEndpoint.stop(1)));
- // Add metrics scope to workflow service stub options
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // Add metrics scope to workflow service stub options, preserving env config
WorkflowServiceStubsOptions stubOptions =
- WorkflowServiceStubsOptions.newBuilder().setMetricsScope(scope).build();
+ WorkflowServiceStubsOptions.newBuilder(profile.toWorkflowServiceStubsOptions())
+ .setMetricsScope(scope)
+ .build();
WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(stubOptions);
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java
index ecee1ad05..d67014f80 100644
--- a/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java
+++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java
@@ -1,9 +1,11 @@
package io.temporal.samples.moneybatch;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class AccountActivityWorker {
@@ -11,8 +13,17 @@ public class AccountActivityWorker {
@SuppressWarnings("CatchAndPrintStackTrace")
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker(TASK_QUEUE);
diff --git a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java
index d9c5ef7cd..99529467d 100644
--- a/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java
+++ b/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java
@@ -1,16 +1,27 @@
package io.temporal.samples.moneybatch;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class AccountTransferWorker {
@SuppressWarnings("CatchAndPrintStackTrace")
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker(AccountActivityWorker.TASK_QUEUE);
diff --git a/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java b/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java
index 8a63c02e3..31b2f507f 100644
--- a/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java
+++ b/core/src/main/java/io/temporal/samples/moneybatch/TransferRequester.java
@@ -3,7 +3,9 @@
import io.temporal.client.BatchRequest;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
import java.util.Random;
import java.util.UUID;
@@ -16,8 +18,18 @@ public class TransferRequester {
public static void main(String[] args) {
String reference = UUID.randomUUID().toString();
int amountCents = (new Random().nextInt(5) + 1) * 25;
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient workflowClient = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient workflowClient =
+ WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
String from = "account1";
String to = "account2";
diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java
index a2bbee418..a3113fe5d 100644
--- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java
+++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java
@@ -1,9 +1,11 @@
package io.temporal.samples.moneytransfer;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class AccountActivityWorker {
@@ -11,10 +13,19 @@ public class AccountActivityWorker {
@SuppressWarnings("CatchAndPrintStackTrace")
public static void main(String[] args) {
- // gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // gRPC stubs wrapper that talks to the temporal service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// worker factory that can be used to create workers for specific task queues
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java
index 6d237d8fa..97ab56ff9 100644
--- a/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java
+++ b/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java
@@ -3,19 +3,30 @@
import static io.temporal.samples.moneytransfer.AccountActivityWorker.TASK_QUEUE;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class AccountTransferWorker {
@SuppressWarnings("CatchAndPrintStackTrace")
public static void main(String[] args) {
// Get worker to poll the common task queue.
- // gRPC stubs wrapper that talks to the local docker instance of temporal service.
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ // gRPC stubs wrapper that talks to the temporal service.
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient client = WorkflowClient.newInstance(service);
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// worker factory that can be used to create workers for specific task queues
WorkerFactory factory = WorkerFactory.newInstance(client);
diff --git a/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java b/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java
index b333b9341..6fda6598e 100644
--- a/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java
+++ b/core/src/main/java/io/temporal/samples/moneytransfer/TransferRequester.java
@@ -4,7 +4,9 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
import java.util.Random;
import java.util.UUID;
@@ -21,9 +23,19 @@ public static void main(String[] args) {
reference = args[0];
amountCents = Integer.parseInt(args[1]);
}
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// client that can be used to start and signal workflows
- WorkflowClient workflowClient = WorkflowClient.newInstance(service);
+ WorkflowClient workflowClient =
+ WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// now we can start running instances of the saga - its state will be persisted
WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build();
diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java
index be1cc788e..f207d64cf 100644
--- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java
+++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java
@@ -4,7 +4,7 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.samples.nexus.options.ClientOptions;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,11 +26,12 @@ public static void main(String[] args) {
logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo 👋"));
HelloCallerWorkflow helloWorkflow =
client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions);
- execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN);
+ execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN);
logger.info(
"Started HelloCallerWorkflow workflowId: {} runId: {}",
execution.getWorkflowId(),
execution.getRunId());
- logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES));
+ logger.info(
+ "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES));
}
}
diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java
index 55186489e..5480917ba 100644
--- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java
+++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java
@@ -21,7 +21,7 @@ public static void main(String[] args) {
WorkflowImplementationOptions.newBuilder()
.setNexusServiceOptions(
Collections.singletonMap(
- "NexusService",
+ "SampleNexusService",
NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build()))
.build(),
EchoCallerWorkflowImpl.class,
diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java
index 948008772..f76edbfe4 100644
--- a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java
@@ -1,15 +1,15 @@
package io.temporal.samples.nexus.caller;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.NexusOperationOptions;
import io.temporal.workflow.NexusServiceOptions;
import io.temporal.workflow.Workflow;
import java.time.Duration;
public class EchoCallerWorkflowImpl implements EchoCallerWorkflow {
- NexusService nexusService =
+ SampleNexusService sampleNexusService =
Workflow.newNexusServiceStub(
- NexusService.class,
+ SampleNexusService.class,
NexusServiceOptions.newBuilder()
.setOperationOptions(
NexusOperationOptions.newBuilder()
@@ -19,6 +19,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow {
@Override
public String echo(String message) {
- return nexusService.echo(new NexusService.EchoInput(message)).getMessage();
+ return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage();
}
}
diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java
index 173c0be8b..1f78e9c02 100644
--- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java
+++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java
@@ -1,11 +1,11 @@
package io.temporal.samples.nexus.caller;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
@WorkflowInterface
public interface HelloCallerWorkflow {
@WorkflowMethod
- String hello(String message, NexusService.Language language);
+ String hello(String message, SampleNexusService.Language language);
}
diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java
index f1612e359..6a6fe8dce 100644
--- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java
@@ -1,6 +1,6 @@
package io.temporal.samples.nexus.caller;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.NexusOperationHandle;
import io.temporal.workflow.NexusOperationOptions;
import io.temporal.workflow.NexusServiceOptions;
@@ -8,9 +8,9 @@
import java.time.Duration;
public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
- NexusService nexusService =
+ SampleNexusService sampleNexusService =
Workflow.newNexusServiceStub(
- NexusService.class,
+ SampleNexusService.class,
NexusServiceOptions.newBuilder()
.setOperationOptions(
NexusOperationOptions.newBuilder()
@@ -19,10 +19,10 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
.build());
@Override
- public String hello(String message, NexusService.Language language) {
- NexusOperationHandle handle =
+ public String hello(String message, SampleNexusService.Language language) {
+ NexusOperationHandle handle =
Workflow.startNexusOperation(
- nexusService::hello, new NexusService.HelloInput(message, language));
+ sampleNexusService::hello, new SampleNexusService.HelloInput(message, language));
// Optionally wait for the operation to be started. NexusOperationExecution will contain the
// operation token in case this operation is asynchronous.
handle.getExecution().get();
diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java
new file mode 100644
index 000000000..74b6f6c69
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java
@@ -0,0 +1,7 @@
+package io.temporal.samples.nexus.handler;
+
+import io.temporal.samples.nexus.service.SampleNexusService;
+
+public interface EchoClient {
+ SampleNexusService.EchoOutput echo(SampleNexusService.EchoInput input);
+}
diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java
new file mode 100644
index 000000000..1c9a2e524
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java
@@ -0,0 +1,12 @@
+package io.temporal.samples.nexus.handler;
+
+import io.temporal.samples.nexus.service.SampleNexusService;
+
+// Note that this is a class, not a Temporal worker. This is to demonstrate that Nexus services can
+// simply call a class instead of a worker for fast operations that don't need retry handling.
+public class EchoClientImpl implements EchoClient {
+ @Override
+ public SampleNexusService.EchoOutput echo(SampleNexusService.EchoInput input) {
+ return new SampleNexusService.EchoOutput(input.getMessage());
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java
index 3d8afa3d7..656b18c65 100644
--- a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java
+++ b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java
@@ -15,7 +15,7 @@ public static void main(String[] args) {
Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class);
- worker.registerNexusServiceImplementation(new NexusServiceImpl());
+ worker.registerNexusServiceImplementation(new SampleNexusServiceImpl());
factory.start();
}
diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java
index 3cae13b31..2c85d0792 100644
--- a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java
+++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java
@@ -1,11 +1,11 @@
package io.temporal.samples.nexus.handler;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
@WorkflowInterface
public interface HelloHandlerWorkflow {
@WorkflowMethod
- NexusService.HelloOutput hello(NexusService.HelloInput input);
+ SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input);
}
diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java
index c897a5181..b896ab523 100644
--- a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java
@@ -1,22 +1,22 @@
package io.temporal.samples.nexus.handler;
import io.temporal.failure.ApplicationFailure;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow {
@Override
- public NexusService.HelloOutput hello(NexusService.HelloInput input) {
+ public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) {
switch (input.getLanguage()) {
case EN:
- return new NexusService.HelloOutput("Hello " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Hello " + input.getName() + " 👋");
case FR:
- return new NexusService.HelloOutput("Bonjour " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " 👋");
case DE:
- return new NexusService.HelloOutput("Hallo " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " 👋");
case ES:
- return new NexusService.HelloOutput("¡Hola! " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("¡Hola! " + input.getName() + " 👋");
case TR:
- return new NexusService.HelloOutput("Merhaba " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " 👋");
}
throw ApplicationFailure.newFailure(
"Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE");
diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java
similarity index 62%
rename from core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java
rename to core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java
index 2344f27ec..42952b72b 100644
--- a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java
@@ -6,27 +6,43 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.nexus.Nexus;
import io.temporal.nexus.WorkflowRunOperation;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
// To create a service implementation, annotate the class with @ServiceImpl and provide the
// interface that the service implements. The service implementation class should have methods that
// return OperationHandler that correspond to the operations defined in the service interface.
-@ServiceImpl(service = NexusService.class)
-public class NexusServiceImpl {
+@ServiceImpl(service = SampleNexusService.class)
+public class SampleNexusServiceImpl {
+ private final EchoClient echoClient;
+
+ // The injected EchoClient makes this class unit-testable.
+ // The no-arg constructor provides a default; the second allows tests to inject a mock.
+ // If you are not using the sync call or do not need to mock a handler, then you will not
+ // need this constructor pairing.
+ public SampleNexusServiceImpl() {
+ this(new EchoClientImpl());
+ }
+
+ public SampleNexusServiceImpl(EchoClient echoClient) {
+ this.echoClient = echoClient;
+ }
+
+ // The Echo Nexus Service exemplifies making a synchronous call using OperationHandler.sync.
+ // In this case, it is calling the EchoClient class - not a workflow - and simply returning the
+ // result.
@OperationImpl
- public OperationHandler echo() {
- // OperationHandler.sync is a meant for exposing simple RPC handlers.
+ public OperationHandler echo() {
return OperationHandler.sync(
// The method is for making arbitrary short calls to other services or databases, or
// perform simple computations such as this one. Users can also access a workflow client by
// calling
// Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as
// signaling, querying, or listing workflows.
- (ctx, details, input) -> new NexusService.EchoOutput(input.getMessage()));
+ (ctx, details, input) -> echoClient.echo(input));
}
@OperationImpl
- public OperationHandler hello() {
+ public OperationHandler hello() {
// Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest
// way to expose a workflow as an operation. To expose a workflow with a different input
// parameters then the operation or from an untyped stub, use the
@@ -39,10 +55,8 @@ public OperationHandler hello
.newWorkflowStub(
HelloHandlerWorkflow.class,
// Workflow IDs should typically be business meaningful IDs and are used to
- // dedupe workflow starts.
- // For this example, we're using the request ID allocated by Temporal when
- // the
- // caller workflow schedules
+ // dedupe workflow starts. For this example, we're using the request ID
+ // allocated by Temporal when the caller workflow schedules
// the operation, this ID is guaranteed to be stable across retries of this
// operation.
//
diff --git a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java b/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java
similarity index 97%
rename from core/src/main/java/io/temporal/samples/nexus/service/NexusService.java
rename to core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java
index ad65b1b33..180f9ec28 100644
--- a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java
+++ b/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java
@@ -6,7 +6,7 @@
import io.nexusrpc.Service;
@Service
-public interface NexusService {
+public interface SampleNexusService {
enum Language {
EN,
FR,
diff --git a/core/src/main/java/io/temporal/samples/nexus/service/description.md b/core/src/main/java/io/temporal/samples/nexus/service/description.md
index d79e151cd..b1cafb3a2 100644
--- a/core/src/main/java/io/temporal/samples/nexus/service/description.md
+++ b/core/src/main/java/io/temporal/samples/nexus/service/description.md
@@ -1,6 +1,6 @@
-## Service: [NexusService](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java)
+## Service: [SampleNexusService](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java)
- operation: `echo`
- operation: `hello`
-See https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java for Input / Output types.
+See https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java for Input / Output types.
diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java
index cb05189cf..811cecde8 100644
--- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java
+++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java
@@ -2,7 +2,7 @@
import io.temporal.client.WorkflowClient;
import io.temporal.samples.nexus.options.ClientOptions;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.worker.WorkflowImplementationOptions;
@@ -22,7 +22,7 @@ public static void main(String[] args) {
WorkflowImplementationOptions.newBuilder()
.setNexusServiceOptions(
Collections.singletonMap(
- NexusService.class.getSimpleName(),
+ SampleNexusService.class.getSimpleName(),
NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build()))
.build(),
HelloCallerWorkflowImpl.class);
diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java
index 1bea801c8..6072906b4 100644
--- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java
@@ -1,10 +1,10 @@
package io.temporal.samples.nexuscancellation.caller;
-import static io.temporal.samples.nexus.service.NexusService.Language.*;
+import static io.temporal.samples.nexus.service.SampleNexusService.Language.*;
import io.temporal.failure.CanceledFailure;
import io.temporal.failure.NexusOperationFailure;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.*;
import java.time.Duration;
import java.util.ArrayList;
@@ -13,11 +13,11 @@
public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
public static final Logger log = Workflow.getLogger(HelloCallerWorkflowImpl.class);
- private static final NexusService.Language[] languages =
- new NexusService.Language[] {EN, FR, DE, ES, TR};
- NexusService nexusService =
+ private static final SampleNexusService.Language[] languages =
+ new SampleNexusService.Language[] {EN, FR, DE, ES, TR};
+ SampleNexusService sampleNexusService =
Workflow.newNexusServiceStub(
- NexusService.class,
+ SampleNexusService.class,
NexusServiceOptions.newBuilder()
.setOperationOptions(
NexusOperationOptions.newBuilder()
@@ -33,7 +33,7 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
@Override
public String hello(String message) {
- List> results = new ArrayList<>(languages.length);
+ List> results = new ArrayList<>(languages.length);
/*
* Create our CancellationScope. Within this scope we call the nexus operation asynchronously
@@ -42,10 +42,11 @@ public String hello(String message) {
CancellationScope scope =
Workflow.newCancellationScope(
() -> {
- for (NexusService.Language language : languages) {
+ for (SampleNexusService.Language language : languages) {
results.add(
Async.function(
- nexusService::hello, new NexusService.HelloInput(message, language)));
+ sampleNexusService::hello,
+ new SampleNexusService.HelloInput(message, language)));
}
});
@@ -56,7 +57,7 @@ public String hello(String message) {
scope.run();
// We use "anyOf" here to wait for one of the nexus operation invocations to return
- NexusService.HelloOutput result = Promise.anyOf(results).get();
+ SampleNexusService.HelloOutput result = Promise.anyOf(results).get();
// Trigger cancellation of all uncompleted nexus operations invocations within the cancellation
// scope
@@ -67,7 +68,7 @@ public String hello(String message) {
// Note: Once the workflow completes any pending cancellation requests are dropped by the
// server. In general, it is a good practice to wait for all cancellation requests to be
// processed before completing the workflow.
- for (Promise promise : results) {
+ for (Promise promise : results) {
try {
promise.get();
} catch (NexusOperationFailure e) {
diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java
index 8b8949a70..f7d0f6940 100644
--- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java
+++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java
@@ -1,7 +1,7 @@
package io.temporal.samples.nexuscancellation.handler;
import io.temporal.client.WorkflowClient;
-import io.temporal.samples.nexus.handler.NexusServiceImpl;
+import io.temporal.samples.nexus.handler.SampleNexusServiceImpl;
import io.temporal.samples.nexus.options.ClientOptions;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
@@ -16,7 +16,7 @@ public static void main(String[] args) {
Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class);
- worker.registerNexusServiceImplementation(new NexusServiceImpl());
+ worker.registerNexusServiceImplementation(new SampleNexusServiceImpl());
factory.start();
}
diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java
index ca6510f60..de8b93557 100644
--- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java
@@ -3,7 +3,7 @@
import io.temporal.failure.ApplicationFailure;
import io.temporal.failure.CanceledFailure;
import io.temporal.samples.nexus.handler.HelloHandlerWorkflow;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.Workflow;
import java.time.Duration;
import org.slf4j.Logger;
@@ -12,21 +12,21 @@ public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow {
public static final Logger log = Workflow.getLogger(HelloHandlerWorkflowImpl.class);
@Override
- public NexusService.HelloOutput hello(NexusService.HelloInput input) {
+ public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) {
// Sleep for a random duration to simulate some work
try {
Workflow.sleep(Duration.ofSeconds(Workflow.newRandom().nextInt(5)));
switch (input.getLanguage()) {
case EN:
- return new NexusService.HelloOutput("Hello " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Hello " + input.getName() + " 👋");
case FR:
- return new NexusService.HelloOutput("Bonjour " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " 👋");
case DE:
- return new NexusService.HelloOutput("Hallo " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " 👋");
case ES:
- return new NexusService.HelloOutput("¡Hola! " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("¡Hola! " + input.getName() + " 👋");
case TR:
- return new NexusService.HelloOutput("Merhaba " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " 👋");
}
throw ApplicationFailure.newFailure(
"Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE");
diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD
index 79453cc4d..54e2bc4f9 100644
--- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD
+++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD
@@ -40,6 +40,6 @@ INFO i.t.s.n.caller.CallerStarter - Workflow result: Hello Nexus 👋
And this on the handler side:
```
-INFO i.t.s.n.handler.NexusServiceImpl - Echo called from a workflow with ID : 7ac97cb9-b457-4052-af94-d82478c35c5e
+INFO i.t.s.n.handler.SampleNexusServiceImpl - Echo called from a workflow with ID : 7ac97cb9-b457-4052-af94-d82478c35c5e
INFO i.t.s.n.h.HelloHandlerWorkflowImpl - HelloHandlerWorkflow called from a workflow with ID : 9e0bc89c-5709-4742-b7c0-868464c2fccf
```
diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java
index f0896221a..cfcc739de 100644
--- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java
+++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java
@@ -7,7 +7,7 @@
import io.temporal.samples.nexus.caller.EchoCallerWorkflow;
import io.temporal.samples.nexus.caller.HelloCallerWorkflow;
import io.temporal.samples.nexus.options.ClientOptions;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.samples.nexuscontextpropagation.propagation.MDCContextPropagator;
import java.util.Collections;
import org.slf4j.Logger;
@@ -35,11 +35,12 @@ public static void main(String[] args) {
logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo 👋"));
HelloCallerWorkflow helloWorkflow =
client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions);
- execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN);
+ execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN);
logger.info(
"Started HelloCallerWorkflow workflowId: {} runId: {}",
execution.getWorkflowId(),
execution.getRunId());
- logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES));
+ logger.info(
+ "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES));
}
}
diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java
index 13e568822..db3f1cfb9 100644
--- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java
+++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java
@@ -28,7 +28,7 @@ public static void main(String[] args) {
WorkflowImplementationOptions.newBuilder()
.setNexusServiceOptions(
Collections.singletonMap(
- "NexusService",
+ "SampleNexusService",
NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build()))
.build(),
EchoCallerWorkflowImpl.class,
diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java
index 14e998629..3de27350d 100644
--- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java
@@ -1,7 +1,7 @@
package io.temporal.samples.nexuscontextpropagation.caller;
import io.temporal.samples.nexus.caller.EchoCallerWorkflow;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.NexusOperationOptions;
import io.temporal.workflow.NexusServiceOptions;
import io.temporal.workflow.Workflow;
@@ -9,9 +9,9 @@
import org.slf4j.MDC;
public class EchoCallerWorkflowImpl implements EchoCallerWorkflow {
- NexusService nexusService =
+ SampleNexusService sampleNexusService =
Workflow.newNexusServiceStub(
- NexusService.class,
+ SampleNexusService.class,
NexusServiceOptions.newBuilder()
.setOperationOptions(
NexusOperationOptions.newBuilder()
@@ -22,6 +22,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow {
@Override
public String echo(String message) {
MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId());
- return nexusService.echo(new NexusService.EchoInput(message)).getMessage();
+ return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage();
}
}
diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java
index fedefbc34..b817179a4 100644
--- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java
@@ -1,7 +1,7 @@
package io.temporal.samples.nexuscontextpropagation.caller;
import io.temporal.samples.nexus.caller.HelloCallerWorkflow;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.NexusOperationHandle;
import io.temporal.workflow.NexusOperationOptions;
import io.temporal.workflow.NexusServiceOptions;
@@ -10,9 +10,9 @@
import org.slf4j.MDC;
public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
- NexusService nexusService =
+ SampleNexusService sampleNexusService =
Workflow.newNexusServiceStub(
- NexusService.class,
+ SampleNexusService.class,
NexusServiceOptions.newBuilder()
.setOperationOptions(
NexusOperationOptions.newBuilder()
@@ -21,11 +21,11 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
.build());
@Override
- public String hello(String message, NexusService.Language language) {
+ public String hello(String message, SampleNexusService.Language language) {
MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId());
- NexusOperationHandle handle =
+ NexusOperationHandle handle =
Workflow.startNexusOperation(
- nexusService::hello, new NexusService.HelloInput(message, language));
+ sampleNexusService::hello, new SampleNexusService.HelloInput(message, language));
// Optionally wait for the operation to be started. NexusOperationExecution will contain the
// operation token in case this operation is asynchronous.
handle.getExecution().get();
diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java
index c4f9ef54c..31b665a8a 100644
--- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java
+++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java
@@ -29,7 +29,7 @@ public static void main(String[] args) {
Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class);
- worker.registerNexusServiceImplementation(new NexusServiceImpl());
+ worker.registerNexusServiceImplementation(new SampleNexusServiceImpl());
factory.start();
}
diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java
index a2db3cb0e..324ad34c1 100644
--- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java
@@ -2,7 +2,7 @@
import io.temporal.failure.ApplicationFailure;
import io.temporal.samples.nexus.handler.HelloHandlerWorkflow;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.Workflow;
import org.slf4j.Logger;
import org.slf4j.MDC;
@@ -11,7 +11,7 @@ public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow {
public static final Logger log = Workflow.getLogger(HelloHandlerWorkflowImpl.class);
@Override
- public NexusService.HelloOutput hello(NexusService.HelloInput input) {
+ public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) {
if (MDC.get("x-nexus-caller-workflow-id") != null) {
log.info(
"HelloHandlerWorkflow called from a workflow with ID : {}",
@@ -19,15 +19,15 @@ public NexusService.HelloOutput hello(NexusService.HelloInput input) {
}
switch (input.getLanguage()) {
case EN:
- return new NexusService.HelloOutput("Hello " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Hello " + input.getName() + " 👋");
case FR:
- return new NexusService.HelloOutput("Bonjour " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " 👋");
case DE:
- return new NexusService.HelloOutput("Hallo " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " 👋");
case ES:
- return new NexusService.HelloOutput("¡Hola! " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("¡Hola! " + input.getName() + " 👋");
case TR:
- return new NexusService.HelloOutput("Merhaba " + input.getName() + " 👋");
+ return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " 👋");
}
throw ApplicationFailure.newFailure(
"Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE");
diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java
similarity index 84%
rename from core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java
rename to core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java
index 4977ff0c0..fc69e756b 100644
--- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java
@@ -7,7 +7,7 @@
import io.temporal.nexus.Nexus;
import io.temporal.nexus.WorkflowRunOperation;
import io.temporal.samples.nexus.handler.HelloHandlerWorkflow;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
@@ -15,12 +15,12 @@
// To create a service implementation, annotate the class with @ServiceImpl and provide the
// interface that the service implements. The service implementation class should have methods that
// return OperationHandler that correspond to the operations defined in the service interface.
-@ServiceImpl(service = NexusService.class)
-public class NexusServiceImpl {
- private static final Logger logger = LoggerFactory.getLogger(NexusServiceImpl.class);
+@ServiceImpl(service = SampleNexusService.class)
+public class SampleNexusServiceImpl {
+ private static final Logger logger = LoggerFactory.getLogger(SampleNexusServiceImpl.class);
@OperationImpl
- public OperationHandler echo() {
+ public OperationHandler echo() {
// OperationHandler.sync is a meant for exposing simple RPC handlers.
return OperationHandler.sync(
// The method is for making arbitrary short calls to other services or databases, or
@@ -33,12 +33,12 @@ public OperationHandler echo()
logger.info(
"Echo called from a workflow with ID : {}", MDC.get("x-nexus-caller-workflow-id"));
}
- return new NexusService.EchoOutput(input.getMessage());
+ return new SampleNexusService.EchoOutput(input.getMessage());
});
}
@OperationImpl
- public OperationHandler hello() {
+ public OperationHandler hello() {
// Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest
// way to expose a workflow as an operation. To expose a workflow with a different input
// parameters then the operation or from an untyped stub, use the
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java
index beebdf406..4d3e7cff5 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java
@@ -7,7 +7,7 @@
import io.temporal.samples.nexus.caller.EchoCallerWorkflow;
import io.temporal.samples.nexus.caller.HelloCallerWorkflow;
import io.temporal.samples.nexus.options.ClientOptions;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,11 +29,12 @@ public static void main(String[] args) {
logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo 👋"));
HelloCallerWorkflow helloWorkflow =
client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions);
- execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN);
+ execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN);
logger.info(
"Started HelloCallerWorkflow workflowId: {} runId: {}",
execution.getWorkflowId(),
execution.getRunId());
- logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES));
+ logger.info(
+ "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES));
}
}
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java
index 1db03a677..64272e6a2 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java
@@ -21,7 +21,7 @@ public static void main(String[] args) {
WorkflowImplementationOptions.newBuilder()
.setNexusServiceOptions(
Collections.singletonMap(
- "NexusService",
+ "SampleNexusService",
NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build()))
.build(),
EchoCallerWorkflowImpl.class,
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java
index ea9aaabb0..20d875ddb 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java
@@ -1,16 +1,16 @@
package io.temporal.samples.nexusmultipleargs.caller;
import io.temporal.samples.nexus.caller.EchoCallerWorkflow;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.NexusOperationOptions;
import io.temporal.workflow.NexusServiceOptions;
import io.temporal.workflow.Workflow;
import java.time.Duration;
public class EchoCallerWorkflowImpl implements EchoCallerWorkflow {
- NexusService nexusService =
+ SampleNexusService sampleNexusService =
Workflow.newNexusServiceStub(
- NexusService.class,
+ SampleNexusService.class,
NexusServiceOptions.newBuilder()
.setOperationOptions(
NexusOperationOptions.newBuilder()
@@ -20,6 +20,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow {
@Override
public String echo(String message) {
- return nexusService.echo(new NexusService.EchoInput(message)).getMessage();
+ return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage();
}
}
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java
index aeb7a13db..03a8635ed 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java
@@ -1,11 +1,11 @@
package io.temporal.samples.nexusmultipleargs.caller;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
@WorkflowInterface
public interface HelloCallerWorkflow {
@WorkflowMethod
- String hello(String message, NexusService.Language language);
+ String hello(String message, SampleNexusService.Language language);
}
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java
index 94f4c3fc5..5d3c0824b 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java
@@ -1,7 +1,7 @@
package io.temporal.samples.nexusmultipleargs.caller;
import io.temporal.samples.nexus.caller.HelloCallerWorkflow;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.NexusOperationHandle;
import io.temporal.workflow.NexusOperationOptions;
import io.temporal.workflow.NexusServiceOptions;
@@ -9,9 +9,9 @@
import java.time.Duration;
public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
- NexusService nexusService =
+ SampleNexusService sampleNexusService =
Workflow.newNexusServiceStub(
- NexusService.class,
+ SampleNexusService.class,
NexusServiceOptions.newBuilder()
.setOperationOptions(
NexusOperationOptions.newBuilder()
@@ -20,10 +20,10 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
.build());
@Override
- public String hello(String message, NexusService.Language language) {
- NexusOperationHandle handle =
+ public String hello(String message, SampleNexusService.Language language) {
+ NexusOperationHandle handle =
Workflow.startNexusOperation(
- nexusService::hello, new NexusService.HelloInput(message, language));
+ sampleNexusService::hello, new SampleNexusService.HelloInput(message, language));
// Optionally wait for the operation to be started. NexusOperationExecution will contain the
// operation token in case this operation is asynchronous.
handle.getExecution().get();
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java
index 0ec77889c..c3fd95e9f 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java
@@ -15,7 +15,7 @@ public static void main(String[] args) {
Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class);
- worker.registerNexusServiceImplementation(new NexusServiceImpl());
+ worker.registerNexusServiceImplementation(new SampleNexusServiceImpl());
factory.start();
}
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java
index 0a443d468..d13906496 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java
@@ -1,11 +1,11 @@
package io.temporal.samples.nexusmultipleargs.handler;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
@WorkflowInterface
public interface HelloHandlerWorkflow {
@WorkflowMethod
- NexusService.HelloOutput hello(String name, NexusService.Language language);
+ SampleNexusService.HelloOutput hello(String name, SampleNexusService.Language language);
}
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java
index b802cee34..9d9cc3733 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java
@@ -1,22 +1,22 @@
package io.temporal.samples.nexusmultipleargs.handler;
import io.temporal.failure.ApplicationFailure;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow {
@Override
- public NexusService.HelloOutput hello(String name, NexusService.Language language) {
+ public SampleNexusService.HelloOutput hello(String name, SampleNexusService.Language language) {
switch (language) {
case EN:
- return new NexusService.HelloOutput("Hello " + name + " 👋");
+ return new SampleNexusService.HelloOutput("Hello " + name + " 👋");
case FR:
- return new NexusService.HelloOutput("Bonjour " + name + " 👋");
+ return new SampleNexusService.HelloOutput("Bonjour " + name + " 👋");
case DE:
- return new NexusService.HelloOutput("Hallo " + name + " 👋");
+ return new SampleNexusService.HelloOutput("Hallo " + name + " 👋");
case ES:
- return new NexusService.HelloOutput("¡Hola! " + name + " 👋");
+ return new SampleNexusService.HelloOutput("¡Hola! " + name + " 👋");
case TR:
- return new NexusService.HelloOutput("Merhaba " + name + " 👋");
+ return new SampleNexusService.HelloOutput("Merhaba " + name + " 👋");
}
throw ApplicationFailure.newFailure(
"Unsupported language: " + language, "UNSUPPORTED_LANGUAGE");
diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java
similarity index 86%
rename from core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java
rename to core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java
index 20d55fed8..b5d819267 100644
--- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java
+++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java
@@ -7,15 +7,15 @@
import io.temporal.nexus.Nexus;
import io.temporal.nexus.WorkflowHandle;
import io.temporal.nexus.WorkflowRunOperation;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.service.SampleNexusService;
// To create a service implementation, annotate the class with @ServiceImpl and provide the
// interface that the service implements. The service implementation class should have methods that
// return OperationHandler that correspond to the operations defined in the service interface.
-@ServiceImpl(service = NexusService.class)
-public class NexusServiceImpl {
+@ServiceImpl(service = SampleNexusService.class)
+public class SampleNexusServiceImpl {
@OperationImpl
- public OperationHandler echo() {
+ public OperationHandler echo() {
// OperationHandler.sync is a meant for exposing simple RPC handlers.
return OperationHandler.sync(
// The method is for making arbitrary short calls to other services or databases, or
@@ -23,11 +23,11 @@ public OperationHandler echo()
// calling
// Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as
// signaling, querying, or listing workflows.
- (ctx, details, input) -> new NexusService.EchoOutput(input.getMessage()));
+ (ctx, details, input) -> new SampleNexusService.EchoOutput(input.getMessage()));
}
@OperationImpl
- public OperationHandler hello() {
+ public OperationHandler hello() {
// If the operation input parameters are different from the workflow input parameters,
// use the WorkflowRunOperation.fromWorkflowHandler constructor and the appropriate constructor
// method on WorkflowHandle to map the Nexus input to the workflow parameters.
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/Packet.java b/core/src/main/java/io/temporal/samples/packetdelivery/Packet.java
new file mode 100644
index 000000000..2d7ee91d4
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/Packet.java
@@ -0,0 +1,21 @@
+package io.temporal.samples.packetdelivery;
+
+public class Packet {
+ private int id;
+ private String content;
+
+ public Packet() {}
+
+ public Packet(int id, String content) {
+ this.id = id;
+ this.content = content;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getContent() {
+ return content;
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDelivery.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDelivery.java
new file mode 100644
index 000000000..334d21bcb
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDelivery.java
@@ -0,0 +1,124 @@
+package io.temporal.samples.packetdelivery;
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.failure.ActivityFailure;
+import io.temporal.failure.CanceledFailure;
+import io.temporal.workflow.*;
+import java.time.Duration;
+import org.slf4j.Logger;
+
+public class PacketDelivery {
+ private Packet packet;
+ private boolean deliveryConfirmation = false;
+ private boolean needDeliveryConfirmation = false;
+ private CompletablePromise delivered = Workflow.newPromise();
+ private CancellationScope cancellationScope;
+
+ private Logger logger = Workflow.getLogger(this.getClass().getName());
+
+ private final PacketDeliveryActivities activities =
+ Workflow.newActivityStub(
+ PacketDeliveryActivities.class,
+ ActivityOptions.newBuilder()
+ .setStartToCloseTimeout(Duration.ofSeconds(5))
+ .setHeartbeatTimeout(Duration.ofSeconds(2))
+ .build());
+
+ private final PacketDeliveryActivities compensationActivities =
+ Workflow.newActivityStub(
+ PacketDeliveryActivities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(3)).build());
+
+ public PacketDelivery(Packet packet) {
+ this.packet = packet;
+ processDeliveryAsync();
+ }
+
+ public Promise getDelivered() {
+ return delivered;
+ }
+
+ public void processDeliveryAsync() {
+ delivered.completeFrom(Async.procedure(this::processDelivery));
+ }
+
+ public void processDelivery() {
+ cancellationScope =
+ Workflow.newCancellationScope(
+ () -> {
+ String deliveryConfirmationResult = "";
+ while (!deliveryConfirmationResult.equals(PacketUtils.COMPLETION_SUCCESS)) {
+ // Step 1 perform delivery
+ logger.info(
+ "** Performing delivery for packet: "
+ + packet.getId()
+ + " - "
+ + packet.getContent());
+ activities.performDelivery(packet);
+ // Step 2 wait for delivery confirmation
+ logger.info(
+ "** Delivery for packet: "
+ + packet.getId()
+ + " - "
+ + packet.getContent()
+ + " awaiting delivery confirmation");
+ needDeliveryConfirmation = true;
+ Workflow.await(() -> deliveryConfirmation);
+ logger.info(
+ "** Delivery for packet: "
+ + packet.getId()
+ + " - "
+ + packet.getContent()
+ + " received confirmation");
+ // Step 3 complete delivery processing
+ logger.info(
+ "** Completing delivery for packet: "
+ + packet.getId()
+ + " - "
+ + packet.getContent());
+ deliveryConfirmationResult = activities.completeDelivery(packet);
+ // Reset deliveryConfirmation and needDeliveryConfirmation
+ deliveryConfirmation = false;
+ needDeliveryConfirmation = false;
+ }
+ });
+
+ try {
+ cancellationScope.run();
+ } catch (Exception e) {
+ if (e instanceof ActivityFailure) {
+ ActivityFailure activityFailure = (ActivityFailure) e;
+ if (activityFailure.getCause() instanceof CanceledFailure) {
+ // Run compensation activity and complete
+ compensationActivities.compensateDelivery(packet);
+ }
+ }
+ // Just for show for example that cancel could come in while we are waiting on approval signal
+ // too
+ else if (e instanceof CanceledFailure) {
+ needDeliveryConfirmation = false;
+ // Run compensation activity and complete
+ compensationActivities.compensateDelivery(packet);
+ }
+ return;
+ }
+ }
+
+ public void confirmDelivery() {
+ this.deliveryConfirmation = true;
+ }
+
+ public void cancelDelivery(String reason) {
+ if (cancellationScope != null) {
+ cancellationScope.cancel(reason);
+ }
+ }
+
+ public boolean isNeedDeliveryConfirmation() {
+ return needDeliveryConfirmation;
+ }
+
+ public Packet getPacket() {
+ return packet;
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivities.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivities.java
new file mode 100644
index 000000000..b2e67dbab
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivities.java
@@ -0,0 +1,15 @@
+package io.temporal.samples.packetdelivery;
+
+import io.temporal.activity.ActivityInterface;
+import java.util.List;
+
+@ActivityInterface
+public interface PacketDeliveryActivities {
+ List generatePackets();
+
+ void performDelivery(Packet packet);
+
+ String completeDelivery(Packet packet);
+
+ String compensateDelivery(Packet packet);
+}
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivitiesImpl.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivitiesImpl.java
new file mode 100644
index 000000000..655223501
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryActivitiesImpl.java
@@ -0,0 +1,161 @@
+package io.temporal.samples.packetdelivery;
+
+import io.temporal.activity.Activity;
+import io.temporal.activity.ActivityExecutionContext;
+import io.temporal.client.ActivityCompletionException;
+import io.temporal.client.WorkflowClient;
+import java.util.*;
+
+public class PacketDeliveryActivitiesImpl implements PacketDeliveryActivities {
+ private List packets =
+ Arrays.asList(
+ new Packet(1, "books"),
+ new Packet(2, "jewelry"),
+ new Packet(3, "furniture"),
+ new Packet(4, "food"),
+ new Packet(5, "electronics"));
+ private WorkflowClient client;
+
+ public PacketDeliveryActivitiesImpl(WorkflowClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public List generatePackets() {
+ return packets;
+ }
+
+ @Override
+ public void performDelivery(Packet packet) {
+ ActivityExecutionContext context = Activity.getExecutionContext();
+ System.out.println(
+ "** Activity - Performing delivery for packet: "
+ + packet.getId()
+ + " with content: "
+ + packet.getContent());
+ for (int i = 0; i < 4; i++) {
+ try {
+ // Perform the heartbeat. Used to notify the workflow that activity execution is alive
+ context.heartbeat(i);
+ } catch (ActivityCompletionException e) {
+ System.out.println(
+ "** Activity - Canceling delivery activity for packet: "
+ + packet.getId()
+ + " with content: "
+ + packet.getContent());
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public String completeDelivery(Packet packet) {
+ ActivityExecutionContext context = Activity.getExecutionContext();
+ System.out.println(
+ "** Activity - Completing delivery for package: "
+ + packet.getId()
+ + " with content: "
+ + packet.getContent());
+ for (int i = 0; i < 4; i++) {
+ try {
+ // Perform the heartbeat. Used to notify the workflow that activity execution is alive
+ context.heartbeat(i);
+ } catch (ActivityCompletionException e) {
+ System.out.println(
+ "** Activity - Canceling complete delivery activity for packet: "
+ + packet.getId()
+ + " with content: "
+ + packet.getContent());
+ throw e;
+ }
+ }
+ // For sample we just confirm
+ return randomCompletionDeliveryResult(packet);
+ }
+
+ @Override
+ public String compensateDelivery(Packet packet) {
+ System.out.println(
+ "** Activity - Compensating delivery for package: "
+ + packet.getId()
+ + " with content: "
+ + packet.getContent());
+ sleep(1);
+ return PacketUtils.COMPENSATION_COMPLETED;
+ }
+
+ /**
+ * For this sample activity completion result can drive if 1. Delivery confirmation is completed,
+ * in which case we complete delivery 2. Delivery confirmation is failed, in which case we run the
+ * delivery again 3. Delivery confirmation is cancelled, in which case we want to cancel delivery
+ * and perform "cleanup activity" Note that any delivery can cancel itself OR another delivery, so
+ * for example Furniure delivery can cancel the Food delivery. For sample we have some specific
+ * rules Which delivery can cancel which
+ */
+ private String randomCompletionDeliveryResult(Packet packet) {
+ Random random = new Random();
+ double randomValue = random.nextDouble();
+ if (randomValue < 0.10) { // 10% chance for delivery completion to be canceled
+ int toCancelDelivery = determineCancelRules(packet);
+ System.out.println(
+ "** Activity - Delivery completion result for package: "
+ + packet.getId()
+ + " with content: "
+ + packet.getContent()
+ + ": "
+ + "Cancelling delivery: "
+ + toCancelDelivery);
+
+ // send cancellation signal for packet to be canceled
+ PacketDeliveryWorkflow packetWorkflow =
+ client.newWorkflowStub(
+ PacketDeliveryWorkflow.class,
+ Activity.getExecutionContext().getInfo().getWorkflowId());
+ packetWorkflow.cancelDelivery(toCancelDelivery, "canceled from delivery " + packet.getId());
+
+ return PacketUtils.COMPLETION_CANCELLED;
+ }
+ if (randomValue < 0.20) { // 20% chance for delivery completion to fail
+ System.out.println(
+ "** Activity - Delivery completion result for package: "
+ + packet.getId()
+ + " with content: "
+ + packet.getContent()
+ + ": "
+ + "Failed");
+ return PacketUtils.COMPLETION_FAILURE;
+ }
+
+ System.out.println(
+ "** Activity - Delivery completion result for package: "
+ + packet.getId()
+ + " with content: "
+ + packet.getContent()
+ + ": "
+ + "Successful");
+ return PacketUtils.COMPLETION_SUCCESS;
+ }
+
+ private void sleep(int seconds) {
+ try {
+ Thread.sleep(seconds * 1000L);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ /**
+ * Sample rules for canceling different deliveries We just rotate the list 1-5 (packet ids) by
+ * packet id and return first result
+ */
+ private int determineCancelRules(Packet packet) {
+ List list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
+ Collections.rotate(list, packet.getId());
+ System.out.println(
+ "** Activity - Package delivery : "
+ + packet.getId()
+ + " canceling package delivery: "
+ + list.get(0));
+ return list.get(0);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflow.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflow.java
new file mode 100644
index 000000000..1f48fac08
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflow.java
@@ -0,0 +1,22 @@
+package io.temporal.samples.packetdelivery;
+
+import io.temporal.workflow.QueryMethod;
+import io.temporal.workflow.SignalMethod;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+import java.util.List;
+
+@WorkflowInterface
+public interface PacketDeliveryWorkflow {
+ @WorkflowMethod
+ String execute();
+
+ @SignalMethod
+ void confirmDelivery(int deliveryId);
+
+ @SignalMethod
+ void cancelDelivery(int deliveryId, String reason);
+
+ @QueryMethod
+ List deliveryConfirmationPackets();
+}
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflowImpl.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflowImpl.java
new file mode 100644
index 000000000..6236458d3
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketDeliveryWorkflowImpl.java
@@ -0,0 +1,79 @@
+package io.temporal.samples.packetdelivery;
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.workflow.Promise;
+import io.temporal.workflow.Workflow;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.slf4j.Logger;
+
+public class PacketDeliveryWorkflowImpl implements PacketDeliveryWorkflow {
+ private final Map packetDeliveries = new HashMap<>();
+ private final Logger logger = Workflow.getLogger(this.getClass().getName());
+
+ private final PacketDeliveryActivities activities =
+ Workflow.newActivityStub(
+ PacketDeliveryActivities.class,
+ ActivityOptions.newBuilder()
+ .setStartToCloseTimeout(Duration.ofSeconds(5))
+ .setHeartbeatTimeout(Duration.ofSeconds(2))
+ .build());
+
+ @Override
+ public String execute() {
+ List> packetsDelivered = new ArrayList<>();
+ // Step 1 - upload initial packets to deliver
+ List initialPackets = activities.generatePackets();
+ // Step 2 - set up delivery processing
+ for (Packet packet : initialPackets) {
+ PacketDelivery delivery = new PacketDelivery(packet);
+ packetDeliveries.put(packet.getId(), delivery);
+ packetsDelivered.add(delivery.getDelivered());
+ }
+
+ // Wait for all packet deliveries to complete
+ Promise.allOf(packetsDelivered).get();
+ return "completed";
+ }
+
+ @Override
+ public void confirmDelivery(int deliveryId) {
+ if (packetDeliveries.containsKey(deliveryId)) {
+ packetDeliveries.get(deliveryId).confirmDelivery();
+ }
+ }
+
+ @Override
+ public void cancelDelivery(int deliveryId, String reason) {
+ if (packetDeliveries.containsKey(deliveryId)) {
+ // Only makes sense to cancel if delivery is not done yet
+ if (!packetDeliveries.get(deliveryId).getDelivered().isCompleted()) {
+ logger.info("Sending cancellation for delivery : " + deliveryId + " and reason: " + reason);
+ packetDeliveries.get(deliveryId).cancelDelivery(reason);
+ }
+ logger.info(
+ "Bypassing sending cancellation for delivery : "
+ + deliveryId
+ + " and reason: "
+ + reason
+ + " because delivery already completed");
+ }
+ }
+
+ @Override
+ public List deliveryConfirmationPackets() {
+ List confirmationPackets = new ArrayList<>();
+ packetDeliveries
+ .values()
+ .forEach(
+ p -> {
+ if (p.isNeedDeliveryConfirmation()) {
+ confirmationPackets.add(p.getPacket());
+ }
+ });
+ return confirmationPackets;
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/PacketUtils.java b/core/src/main/java/io/temporal/samples/packetdelivery/PacketUtils.java
new file mode 100644
index 000000000..193a2f4be
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/PacketUtils.java
@@ -0,0 +1,8 @@
+package io.temporal.samples.packetdelivery;
+
+public class PacketUtils {
+ public static String COMPLETION_SUCCESS = "Delivery Completion Successful";
+ public static String COMPLETION_FAILURE = "Delivery Completion Failed";
+ public static String COMPLETION_CANCELLED = "Delivery Completion Cancelled";
+ public static String COMPENSATION_COMPLETED = "Delivery Compensation Completed";
+}
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/README.md b/core/src/main/java/io/temporal/samples/packetdelivery/README.md
new file mode 100644
index 000000000..d43309990
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/README.md
@@ -0,0 +1,24 @@
+# Async Package Delivery Sample
+
+This sample show how to run multiple "paths" of execution async within single workflow.
+Sample starts deliveries of 5 items in parallel. Each item performs an activity
+and then waits for a confirmation signal, then performs second activity.
+
+Workflow waits until all packets have been delivered. Each packet delivery path can choose to
+also "cancel" delivery of another item. This is done via signal and cancellation of the
+CancellationScope.
+
+## Notes
+1. In this sample we do not handle event history count and size partitioning via ContinueAsNew. It is assumed
+that the total number of paths and path lengths (in terms of activity executions) would not exceed it.
+For your use case you might need to add ContinueAsNew checks to deal with this situation.
+2. Use this sample as all other ones as reference for your implementation. It was not tested on high scale
+so using it as-is without load testing is not recommended.
+
+## Start the Sample:
+```bash
+./gradlew -q execute -PmainClass=io.temporal.samples.packetdelivery.Starter
+```
+
+Run sample multiple times to see different scenarios (delivery failure and retry and delivery cancelation)
+There is a 10% chance delivery is going to be canceled and 20% chane it will fail.
\ No newline at end of file
diff --git a/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java b/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java
new file mode 100644
index 000000000..f6ca6000d
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/packetdelivery/Starter.java
@@ -0,0 +1,81 @@
+package io.temporal.samples.packetdelivery;
+
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowNotFoundException;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+public class Starter {
+ public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+ Worker worker = factory.newWorker("packet-delivery-taskqueue");
+
+ worker.registerWorkflowImplementationTypes(PacketDeliveryWorkflowImpl.class);
+ worker.registerActivitiesImplementations(new PacketDeliveryActivitiesImpl(client));
+
+ factory.start();
+
+ PacketDeliveryWorkflow workflow =
+ client.newWorkflowStub(
+ PacketDeliveryWorkflow.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId("packet-delivery-workflow")
+ .setTaskQueue("packet-delivery-taskqueue")
+ .build());
+
+ WorkflowClient.start(workflow::execute);
+
+ // start completing package deliveries (send confirmations)
+ // Query workflow for packets that need confirmation, confirm until none need confirmation any
+ // more
+ while (true) {
+ sleep(3);
+ List packets = workflow.deliveryConfirmationPackets();
+ if (packets.isEmpty()) {
+ break;
+ }
+ // for "fun", reverse the list we get from delivery confirmation list
+ Collections.reverse(packets);
+
+ for (Packet p : packets) {
+ try {
+ workflow.confirmDelivery(p.getId());
+ } catch (WorkflowNotFoundException e) {
+ // In some cases with cancellations happening, workflow could be completed by now
+ // We just ignore and exit out of loop
+ break;
+ }
+ }
+ }
+
+ // wait for workflow to complete
+ String result = WorkflowStub.fromTyped(workflow).getResult(String.class);
+ System.out.println("** Workflow Result: " + result);
+ }
+
+ private static void sleep(int seconds) {
+ try {
+ Thread.sleep(seconds * 1000L);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java
index 2e17f4cb0..e9e368a3b 100644
--- a/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java
+++ b/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/Starter.java
@@ -7,9 +7,11 @@
import io.temporal.client.WorkflowClientOptions;
import io.temporal.client.WorkflowOptions;
import io.temporal.common.converter.DefaultDataConverter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -20,7 +22,16 @@ public class Starter {
private static final String TASK_QUEUE = "CloudEventsConverterQueue";
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// Add CloudEventsPayloadConverter
// It has the same encoding type as JacksonJsonPayloadConverter
diff --git a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java
index dffdb41a1..4a5e121ef 100644
--- a/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java
+++ b/core/src/main/java/io/temporal/samples/payloadconverter/crypto/Starter.java
@@ -9,16 +9,27 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.common.converter.DefaultDataConverter;
import io.temporal.common.converter.JacksonJsonPayloadConverter;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class Starter {
private static final String TASK_QUEUE = "CryptoConverterQueue";
private static final String encryptDecryptPassword = "encryptDecryptPassword";
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
// Set crypto data converter in client options
WorkflowClient client =
diff --git a/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java b/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java
index 7db5df86d..58062c176 100644
--- a/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java
+++ b/core/src/main/java/io/temporal/samples/peractivityoptions/Starter.java
@@ -5,20 +5,32 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.common.RetryOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.worker.WorkflowImplementationOptions;
+import java.io.IOException;
import java.time.Duration;
public class Starter {
public static final String TASK_QUEUE = "perActivityTaskQueue";
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
- private static final WorkerFactory factory = WorkerFactory.newInstance(client);
public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+
// Create Worker
Worker worker = factory.newWorker(TASK_QUEUE);
// Register workflow impl and set the per-activity options
diff --git a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java
index 4a52cab2f..ed8fa477f 100644
--- a/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java
+++ b/core/src/main/java/io/temporal/samples/polling/frequent/FrequentPollingStarter.java
@@ -2,15 +2,31 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.polling.PollingWorkflow;
import io.temporal.samples.polling.TestService;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class FrequentPollingStarter {
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
+ private static WorkflowServiceStubs service;
+ private static WorkflowClient client;
+
+ static {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ }
+
private static final String taskQueue = "pollingSampleQueue";
private static final String workflowId = "FrequentPollingSampleWorkflow";
diff --git a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java
index 2a6cb7a85..f778ce287 100644
--- a/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java
+++ b/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingStarter.java
@@ -2,15 +2,31 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.polling.PollingWorkflow;
import io.temporal.samples.polling.TestService;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class InfrequentPollingStarter {
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
+ private static WorkflowServiceStubs service;
+ private static WorkflowClient client;
+
+ static {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ }
+
private static final String taskQueue = "pollingSampleQueue";
private static final String workflowId = "InfrequentPollingSampleWorkflow";
diff --git a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java
index 81853ec71..93e3c9e6b 100644
--- a/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java
+++ b/core/src/main/java/io/temporal/samples/polling/infrequentwithretryafter/InfrequentPollingWithRetryAfterStarter.java
@@ -2,15 +2,31 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.polling.PollingWorkflow;
import io.temporal.samples.polling.TestService;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class InfrequentPollingWithRetryAfterStarter {
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
+ private static WorkflowServiceStubs service;
+ private static WorkflowClient client;
+
+ static {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ }
+
private static final String taskQueue = "pollingSampleQueue";
private static final String workflowId = "InfrequentPollingWithRetryAfterWorkflow";
diff --git a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java
index f2ef3eb1f..34c3e8a5a 100644
--- a/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java
+++ b/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingStarter.java
@@ -2,15 +2,31 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.samples.polling.PollingWorkflow;
import io.temporal.samples.polling.TestService;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class PeriodicPollingStarter {
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
+ private static WorkflowServiceStubs service;
+ private static WorkflowClient client;
+
+ static {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ service = WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ }
+
private static final String taskQueue = "pollingSampleQueue";
private static final String workflowId = "PeriodicPollingSampleWorkflow";
diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java
index cd3e546da..c948ba02e 100644
--- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java
+++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java
@@ -3,7 +3,9 @@
import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
/**
* Send signal requesting that an exception thrown from the activity is propagated to the workflow.
@@ -11,8 +13,17 @@
public class FailureRequester {
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// Note that we use the listener interface that the interceptor registered dynamically, not the
// workflow interface.
diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java
index 42fd358bd..55b9ebe17 100644
--- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java
+++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowWorker.java
@@ -2,10 +2,12 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.worker.WorkerFactoryOptions;
+import java.io.IOException;
public class MyWorkflowWorker {
@@ -14,8 +16,17 @@ public class MyWorkflowWorker {
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// Register interceptor with the factory.
WorkerFactoryOptions factoryOptions =
WorkerFactoryOptions.newBuilder()
diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java
index c54f8d0ab..08a7afcbb 100644
--- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java
+++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java
@@ -3,13 +3,24 @@
import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
public class QueryRequester {
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// Note that we use the listener interface that the interceptor registered dynamically, not the
// workflow interface.
diff --git a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java
index b0cf85ef8..a5469d80f 100644
--- a/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java
+++ b/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java
@@ -3,13 +3,24 @@
import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
public class RetryRequester {
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// Note that we use the listener interface that the interceptor registered dynamically, not the
// workflow interface.
diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java
index 1913a3e40..71ae380cb 100644
--- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java
+++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowStarter.java
@@ -7,7 +7,9 @@
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
import io.temporal.client.WorkflowUpdateStage;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -29,8 +31,17 @@ public static void main(String[] args) {
+ " ");
System.exit(1);
}
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
boolean shouldTestContinueAsNew = args.length > 0 ? Boolean.parseBoolean(args[0]) : false;
ClusterManagerWorkflow cluster =
client.newWorkflowStub(
diff --git a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java
index 2f063a663..a4fa8d69f 100644
--- a/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java
+++ b/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java
@@ -1,9 +1,11 @@
package io.temporal.samples.safemessagepassing;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -13,8 +15,17 @@ public class ClusterManagerWorkflowWorker {
static final String CLUSTER_MANAGER_WORKFLOW_ID = "ClusterManagerWorkflow";
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
final Worker worker = factory.newWorker(TASK_QUEUE);
worker.registerWorkflowImplementationTypes(ClusterManagerWorkflowImpl.class);
diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java b/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java
index cf5e9a9a7..91ed89325 100644
--- a/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java
+++ b/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java
@@ -3,15 +3,30 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
public class Starter {
public static final String TASK_QUEUE = "SleepForDaysTaskQueue";
public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+
// Start a workflow execution.
SleepForDaysWorkflow workflow =
- Worker.client.newWorkflowStub(
+ client.newWorkflowStub(
SleepForDaysWorkflow.class,
WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build());
diff --git a/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java b/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java
index 301326c27..b5abac1cb 100644
--- a/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java
+++ b/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java
@@ -1,16 +1,28 @@
package io.temporal.samples.sleepfordays;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
public class Worker {
public static final String TASK_QUEUE = "SleepForDaysTaskQueue";
- public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- public static final WorkflowClient client = WorkflowClient.newInstance(service);
- public static final WorkerFactory factory = WorkerFactory.newInstance(client);
public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+
io.temporal.worker.Worker worker = factory.newWorker(TASK_QUEUE);
worker.registerWorkflowImplementationTypes(SleepForDaysImpl.class);
worker.registerActivitiesImplementations(new SendEmailActivityImpl());
diff --git a/core/src/main/java/io/temporal/samples/ssl/Starter.java b/core/src/main/java/io/temporal/samples/ssl/Starter.java
index c69101473..25b9df6ba 100644
--- a/core/src/main/java/io/temporal/samples/ssl/Starter.java
+++ b/core/src/main/java/io/temporal/samples/ssl/Starter.java
@@ -50,9 +50,9 @@ public static void main(String[] args) throws Exception {
if (refreshPeriod > 0) {
AdvancedTlsX509KeyManager clientKeyManager = new AdvancedTlsX509KeyManager();
// Reload credentials every minute
- clientKeyManager.updateIdentityCredentialsFromFile(
- clientKeyFile,
+ clientKeyManager.updateIdentityCredentials(
clientCertFile,
+ clientKeyFile,
refreshPeriod,
TimeUnit.MINUTES,
Executors.newScheduledThreadPool(1));
diff --git a/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java b/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java
index 20f0d171d..e36a407c7 100644
--- a/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java
+++ b/core/src/main/java/io/temporal/samples/terminateworkflow/Starter.java
@@ -7,21 +7,33 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class Starter {
public static final String TASK_QUEUE = "terminateQueue";
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
- private static final WorkerFactory factory = WorkerFactory.newInstance(client);
public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+
// Create Worker
- createWorker();
+ createWorker(factory);
// Create Workflow options
WorkflowOptions workflowOptions =
@@ -44,13 +56,13 @@ public static void main(String[] args) {
untyped.terminate("Sample reason");
// Check workflow status, should be WORKFLOW_EXECUTION_STATUS_TERMINATED
- System.out.println("Status: " + getStatusAsString(execution));
+ System.out.println("Status: " + getStatusAsString(execution, client, service));
System.exit(0);
}
/** This method creates a Worker from the factory. */
- private static void createWorker() {
+ private static void createWorker(WorkerFactory factory) {
Worker worker = factory.newWorker(TASK_QUEUE);
worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class);
@@ -78,7 +90,8 @@ private static void sleepSeconds(int seconds) {
* @param execution workflow execution
* @return Workflow status
*/
- private static String getStatusAsString(WorkflowExecution execution) {
+ private static String getStatusAsString(
+ WorkflowExecution execution, WorkflowClient client, WorkflowServiceStubs service) {
DescribeWorkflowExecutionRequest describeWorkflowExecutionRequest =
DescribeWorkflowExecutionRequest.newBuilder()
.setNamespace(client.getOptions().getNamespace())
diff --git a/core/src/main/java/io/temporal/samples/tracing/Starter.java b/core/src/main/java/io/temporal/samples/tracing/Starter.java
index ebb830c19..bb1eaaae3 100644
--- a/core/src/main/java/io/temporal/samples/tracing/Starter.java
+++ b/core/src/main/java/io/temporal/samples/tracing/Starter.java
@@ -4,12 +4,13 @@
import io.temporal.client.WorkflowClientOptions;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.opentracing.OpenTracingClientInterceptor;
import io.temporal.samples.tracing.workflow.TracingWorkflow;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
public class Starter {
- public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
public static final String TASK_QUEUE_NAME = "tracingTaskQueue";
public static void main(String[] args) {
@@ -18,9 +19,20 @@ public static void main(String[] args) {
type = args[0];
}
- // Set the OpenTracing client interceptor
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+
+ // Set the OpenTracing client interceptor, preserving env config
WorkflowClientOptions clientOptions =
- WorkflowClientOptions.newBuilder()
+ profile.toWorkflowClientOptions().toBuilder()
.setInterceptors(new OpenTracingClientInterceptor(JaegerUtils.getJaegerOptions(type)))
.build();
WorkflowClient client = WorkflowClient.newInstance(service, clientOptions);
diff --git a/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java b/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java
index 221c3efef..b726bcaae 100644
--- a/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java
+++ b/core/src/main/java/io/temporal/samples/tracing/TracingWorker.java
@@ -1,6 +1,7 @@
package io.temporal.samples.tracing;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.opentracing.OpenTracingWorkerInterceptor;
import io.temporal.samples.tracing.workflow.TracingActivitiesImpl;
import io.temporal.samples.tracing.workflow.TracingChildWorkflowImpl;
@@ -9,10 +10,9 @@
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.worker.WorkerFactoryOptions;
+import java.io.IOException;
public class TracingWorker {
- private static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- private static final WorkflowClient client = WorkflowClient.newInstance(service);
public static final String TASK_QUEUE_NAME = "tracingTaskQueue";
public static void main(String[] args) {
@@ -21,6 +21,18 @@ public static void main(String[] args) {
type = args[0];
}
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+
// Set the OpenTracing client interceptor
WorkerFactoryOptions factoryOptions =
WorkerFactoryOptions.newBuilder()
diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java
index d1f38e1ab..0cd1bb14c 100644
--- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java
+++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowStarter.java
@@ -8,7 +8,9 @@
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowExecutionAlreadyStarted;
import io.temporal.client.WorkflowOptions;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -17,8 +19,17 @@ public class DynamicSleepWorkflowStarter {
private static final Logger logger = LoggerFactory.getLogger(DynamicSleepWorkflowStarter.class);
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
DynamicSleepWorkflow workflow =
client.newWorkflowStub(
diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java
index d0a4e712b..a7db34126 100644
--- a/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java
+++ b/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java
@@ -1,9 +1,11 @@
package io.temporal.samples.updatabletimer;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
+import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -17,8 +19,17 @@ public class DynamicSleepWorkflowWorker {
static final String DYNAMIC_SLEEP_WORKFLOW_ID = "DynamicSleepWorkflow";
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
WorkerFactory factory = WorkerFactory.newInstance(client);
final Worker worker = factory.newWorker(TASK_QUEUE);
worker.registerWorkflowImplementationTypes(DynamicSleepWorkflowImpl.class);
diff --git a/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java b/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java
index 0a13ff071..3a8f935a2 100644
--- a/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java
+++ b/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java
@@ -3,7 +3,9 @@
import static io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker.DYNAMIC_SLEEP_WORKFLOW_ID;
import io.temporal.client.WorkflowClient;
+import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -12,8 +14,17 @@ public class WakeUpTimeUpdater {
private static final Logger logger = LoggerFactory.getLogger(WakeUpTimeUpdater.class);
public static void main(String[] args) {
- WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
- WorkflowClient client = WorkflowClient.newInstance(service);
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
// Create a stub that points to an existing workflow with the given ID
DynamicSleepWorkflow workflow =
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/Activities.java b/core/src/main/java/io/temporal/samples/workerversioning/Activities.java
new file mode 100644
index 000000000..b41189d2a
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/Activities.java
@@ -0,0 +1,38 @@
+package io.temporal.samples.workerversioning;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityMethod;
+
+@ActivityInterface
+public interface Activities {
+
+ @ActivityMethod
+ String someActivity(String calledBy);
+
+ @ActivityMethod
+ String someIncompatibleActivity(IncompatibleActivityInput input);
+
+ class IncompatibleActivityInput {
+ private final String calledBy;
+ private final String moreData;
+
+ @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
+ public IncompatibleActivityInput(
+ @JsonProperty("calledBy") String calledBy, @JsonProperty("moreData") String moreData) {
+ this.calledBy = calledBy;
+ this.moreData = moreData;
+ }
+
+ @JsonProperty("calledBy")
+ public String getCalledBy() {
+ return calledBy;
+ }
+
+ @JsonProperty("moreData")
+ public String getMoreData() {
+ return moreData;
+ }
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/ActivitiesImpl.java b/core/src/main/java/io/temporal/samples/workerversioning/ActivitiesImpl.java
new file mode 100644
index 000000000..b3e4e2c28
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/ActivitiesImpl.java
@@ -0,0 +1,25 @@
+package io.temporal.samples.workerversioning;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ActivitiesImpl implements Activities {
+
+ private static final Logger logger = LoggerFactory.getLogger(ActivitiesImpl.class);
+
+ @Override
+ public String someActivity(String calledBy) {
+ logger.info("SomeActivity called by {}", calledBy);
+ return "SomeActivity called by " + calledBy;
+ }
+
+ @Override
+ public String someIncompatibleActivity(IncompatibleActivityInput input) {
+ logger.info(
+ "SomeIncompatibleActivity called by {} with {}", input.getCalledBy(), input.getMoreData());
+ return "SomeIncompatibleActivity called by "
+ + input.getCalledBy()
+ + " with "
+ + input.getMoreData();
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflow.java b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflow.java
new file mode 100644
index 000000000..8dff5f7cd
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflow.java
@@ -0,0 +1,15 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.workflow.SignalMethod;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+
+@WorkflowInterface
+public interface AutoUpgradingWorkflow {
+
+ @WorkflowMethod
+ void run();
+
+ @SignalMethod
+ void doNextSignal(String signal);
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1Impl.java b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1Impl.java
new file mode 100644
index 000000000..645f0f70d
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1Impl.java
@@ -0,0 +1,52 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.common.VersioningBehavior;
+import io.temporal.workflow.Workflow;
+import io.temporal.workflow.WorkflowVersioningBehavior;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+
+/**
+ * This workflow will automatically move to the latest worker version. We'll be making changes to
+ * it, which must be replay safe. Note that generally you won't want or need to include a version
+ * number in your workflow name if you're using the worker versioning feature. This sample does it
+ * to illustrate changes to the same code over time - but really what we're demonstrating here is
+ * the evolution of what would have been one workflow definition.
+ */
+public class AutoUpgradingWorkflowV1Impl implements AutoUpgradingWorkflow {
+
+ private static final Logger logger = Workflow.getLogger(AutoUpgradingWorkflowV1Impl.class);
+
+ private final List signals = new ArrayList<>();
+ private final Activities activities =
+ Workflow.newActivityStub(
+ Activities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build());
+
+ @Override
+ @WorkflowVersioningBehavior(VersioningBehavior.AUTO_UPGRADE)
+ public void run() {
+ logger.info("Changing workflow v1 started. StartTime: {}", Workflow.currentTimeMillis());
+
+ while (true) {
+ Workflow.await(() -> !signals.isEmpty());
+ String signal = signals.remove(0);
+
+ if ("do-activity".equals(signal)) {
+ logger.info("Changing workflow v1 running activity");
+ activities.someActivity("v1");
+ } else {
+ logger.info("Concluding workflow v1");
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void doNextSignal(String signal) {
+ signals.add(signal);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1bImpl.java b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1bImpl.java
new file mode 100644
index 000000000..abedf8517
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/AutoUpgradingWorkflowV1bImpl.java
@@ -0,0 +1,65 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.common.VersioningBehavior;
+import io.temporal.workflow.Workflow;
+import io.temporal.workflow.WorkflowVersioningBehavior;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+
+/**
+ * This represents us having made *compatible* changes to AutoUpgradingWorkflowV1Impl.
+ *
+ * The compatible changes we've made are:
+ *
+ *
+ * - Altering the log lines
+ *
- Using the `Workflow.getVersion` API to properly introduce branching behavior while
+ * maintaining compatibility
+ *
+ */
+public class AutoUpgradingWorkflowV1bImpl implements AutoUpgradingWorkflow {
+
+ private static final Logger logger = Workflow.getLogger(AutoUpgradingWorkflowV1bImpl.class);
+
+ private final List signals = new ArrayList<>();
+ private final Activities activities =
+ Workflow.newActivityStub(
+ Activities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build());
+
+ @Override
+ @WorkflowVersioningBehavior(VersioningBehavior.AUTO_UPGRADE)
+ public void run() {
+ logger.info("Changing workflow v1b started. StartTime: {}", Workflow.currentTimeMillis());
+
+ while (true) {
+ Workflow.await(() -> !signals.isEmpty());
+ String signal = signals.remove(0);
+
+ if ("do-activity".equals(signal)) {
+ logger.info("Changing workflow v1b running activity");
+ int version = Workflow.getVersion("DifferentActivity", Workflow.DEFAULT_VERSION, 1);
+ if (version == 1) {
+ activities.someIncompatibleActivity(
+ new Activities.IncompatibleActivityInput("v1b", "hello!"));
+ } else {
+ // Note it is a valid compatible change to alter the input to an activity.
+ // However, because we're using the getVersion API, this branch will never be
+ // taken.
+ activities.someActivity("v1b");
+ }
+ } else {
+ logger.info("Concluding workflow v1b");
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void doNextSignal(String signal) {
+ signals.add(signal);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflow.java b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflow.java
new file mode 100644
index 000000000..1d930a40e
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflow.java
@@ -0,0 +1,15 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.workflow.SignalMethod;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+
+@WorkflowInterface
+public interface PinnedWorkflow {
+
+ @WorkflowMethod
+ void run();
+
+ @SignalMethod
+ void doNextSignal(String signal);
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV1Impl.java b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV1Impl.java
new file mode 100644
index 000000000..4826f715c
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV1Impl.java
@@ -0,0 +1,49 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.common.VersioningBehavior;
+import io.temporal.workflow.Workflow;
+import io.temporal.workflow.WorkflowVersioningBehavior;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+
+/**
+ * This workflow represents one that likely has a short lifetime, and we want to always stay pinned
+ * to the same version it began on. Note that generally you won't want or need to include a version
+ * number in your workflow name if you're using the worker versioning feature. This sample does it
+ * to illustrate changes to the same code over time - but really what we're demonstrating here is
+ * the evolution of what would have been one workflow definition.
+ */
+public class PinnedWorkflowV1Impl implements PinnedWorkflow {
+
+ private static final Logger logger = Workflow.getLogger(PinnedWorkflowV1Impl.class);
+
+ private final List signals = new ArrayList<>();
+ private final Activities activities =
+ Workflow.newActivityStub(
+ Activities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build());
+
+ @Override
+ @WorkflowVersioningBehavior(VersioningBehavior.PINNED)
+ public void run() {
+ logger.info("Pinned Workflow v1 started. StartTime: {}", Workflow.currentTimeMillis());
+
+ while (true) {
+ Workflow.await(() -> !signals.isEmpty());
+ String signal = signals.remove(0);
+ if ("conclude".equals(signal)) {
+ break;
+ }
+ }
+
+ activities.someActivity("Pinned-v1");
+ }
+
+ @Override
+ public void doNextSignal(String signal) {
+ signals.add(signal);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV2Impl.java b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV2Impl.java
new file mode 100644
index 000000000..a880b2dc1
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/PinnedWorkflowV2Impl.java
@@ -0,0 +1,51 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.common.VersioningBehavior;
+import io.temporal.workflow.Workflow;
+import io.temporal.workflow.WorkflowVersioningBehavior;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+
+/**
+ * This workflow has changes that would make it incompatible with v1, and aren't protected by a
+ * patch.
+ */
+public class PinnedWorkflowV2Impl implements PinnedWorkflow {
+
+ private static final Logger logger = Workflow.getLogger(PinnedWorkflowV2Impl.class);
+
+ private final List signals = new ArrayList<>();
+ private final Activities activities =
+ Workflow.newActivityStub(
+ Activities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build());
+
+ @Override
+ @WorkflowVersioningBehavior(VersioningBehavior.PINNED)
+ public void run() {
+ logger.info("Pinned Workflow v2 started. StartTime: {}", Workflow.currentTimeMillis());
+
+ // Here we call an activity where we didn't before, which is an incompatible change.
+ activities.someActivity("Pinned-v2");
+
+ while (true) {
+ Workflow.await(() -> !signals.isEmpty());
+ String signal = signals.remove(0);
+ if ("conclude".equals(signal)) {
+ break;
+ }
+ }
+
+ // We've also changed the activity type here, another incompatible change
+ activities.someIncompatibleActivity(
+ new Activities.IncompatibleActivityInput("Pinned-v2", "hi"));
+ }
+
+ @Override
+ public void doNextSignal(String signal) {
+ signals.add(signal);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/README.md b/core/src/main/java/io/temporal/samples/workerversioning/README.md
new file mode 100644
index 000000000..c74b10488
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/README.md
@@ -0,0 +1,26 @@
+# Worker Versioning
+
+This sample demonstrates how to use Temporal's Worker Versioning feature to safely deploy updates to workflow and activity code. It shows the difference between auto-upgrading and pinned workflows, and how to manage worker deployments with different build IDs.
+
+The sample creates multiple worker versions (1.0, 1.1, and 2.0) within one deployment and demonstrates:
+- **Auto-upgrading workflows**: Automatically and controllably migrate to newer worker versions
+- **Pinned workflows**: Stay on the original worker version throughout their lifecycle
+- **Compatible vs incompatible changes**: How to make safe updates using `Workflow.getVersion`
+
+## Steps to run this sample:
+
+1) Run a [Temporal service](https://github.com/temporalio/samples-java/tree/main/#how-to-use). And
+ ensure that you're using at least Server version 1.28.0 (CLI version 1.4.0).
+
+2) Start the main application (this will guide you through the sample):
+ ```bash
+ ./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.Starter
+ ```
+3) Follow the prompts to start workers in separate terminals:
+ - When prompted, run: `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV1`
+ - When prompted, run: `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV1_1`
+ - When prompted, run: `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV2`
+
+Follow the prompts in the example to observe auto-upgrading workflows migrating to newer workers
+while pinned workflows remain on their original versions.
+
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/Starter.java b/core/src/main/java/io/temporal/samples/workerversioning/Starter.java
new file mode 100644
index 000000000..b743cf821
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/Starter.java
@@ -0,0 +1,175 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.api.workflowservice.v1.DescribeWorkerDeploymentRequest;
+import io.temporal.api.workflowservice.v1.DescribeWorkerDeploymentResponse;
+import io.temporal.api.workflowservice.v1.SetWorkerDeploymentCurrentVersionRequest;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.client.WorkflowStub;
+import io.temporal.common.WorkerDeploymentVersion;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import java.io.IOException;
+import java.util.UUID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Starter {
+ public static final String TASK_QUEUE = "worker-versioning";
+ public static final String DEPLOYMENT_NAME = "my-deployment";
+
+ private static final Logger logger = LoggerFactory.getLogger(Starter.class);
+
+ public static void main(String[] args) throws Exception {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+
+ // Wait for v1 worker and set as current version
+ logger.info(
+ "Waiting for v1 worker to appear. Run `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV1` in another terminal");
+ waitForWorkerAndMakeCurrent(client, service, "1.0");
+
+ // Start auto-upgrading and pinned workflows. Importantly, note that when we start the
+ // workflows,
+ // we are using a workflow type name which does *not* include the version number. We defined
+ // them
+ // with versioned names so we could show changes to the code, but here when the client invokes
+ // them, we're demonstrating that the client remains version-agnostic.
+ String autoUpgradeWorkflowId = "worker-versioning-versioning-autoupgrade_" + UUID.randomUUID();
+ WorkflowStub autoUpgradeExecution =
+ client.newUntypedWorkflowStub(
+ "AutoUpgradingWorkflow",
+ WorkflowOptions.newBuilder()
+ .setWorkflowId(autoUpgradeWorkflowId)
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+
+ String pinnedWorkflowId = "worker-versioning-versioning-pinned_" + UUID.randomUUID();
+ WorkflowStub pinnedExecution =
+ client.newUntypedWorkflowStub(
+ "PinnedWorkflow",
+ WorkflowOptions.newBuilder()
+ .setWorkflowId(pinnedWorkflowId)
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+
+ // Start workflows asynchronously
+ autoUpgradeExecution.start();
+ pinnedExecution.start();
+
+ logger.info(
+ "Started auto-upgrading workflow: {}", autoUpgradeExecution.getExecution().getWorkflowId());
+ logger.info("Started pinned workflow: {}", pinnedExecution.getExecution().getWorkflowId());
+
+ // Signal both workflows a few times to drive them
+ advanceWorkflows(autoUpgradeExecution, pinnedExecution);
+
+ // Now wait for the v1.1 worker to appear and become current
+ logger.info(
+ "Waiting for v1.1 worker to appear. Run `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV1_1` in another terminal");
+ waitForWorkerAndMakeCurrent(client, service, "1.1");
+
+ // Once it has, we will continue to advance the workflows.
+ // The auto-upgrade workflow will now make progress on the new worker, while the pinned one will
+ // keep progressing on the old worker.
+ advanceWorkflows(autoUpgradeExecution, pinnedExecution);
+
+ // Finally we'll start the v2 worker, and again it'll become the new current version
+ logger.info(
+ "Waiting for v2 worker to appear. Run `./gradlew -q execute -PmainClass=io.temporal.samples.workerversioning.WorkerV2` in another terminal");
+ waitForWorkerAndMakeCurrent(client, service, "2.0");
+
+ // Once it has we'll start one more new workflow, another pinned one, to demonstrate that new
+ // pinned workflows start on the current version.
+ String pinnedWorkflow2Id = "worker-versioning-versioning-pinned-2_" + UUID.randomUUID();
+ WorkflowStub pinnedExecution2 =
+ client.newUntypedWorkflowStub(
+ "PinnedWorkflow",
+ WorkflowOptions.newBuilder()
+ .setWorkflowId(pinnedWorkflow2Id)
+ .setTaskQueue(TASK_QUEUE)
+ .build());
+ pinnedExecution2.start();
+ logger.info("Started pinned workflow v2: {}", pinnedExecution2.getExecution().getWorkflowId());
+
+ // Now we'll conclude all workflows. You should be able to see in your server UI that the pinned
+ // workflow always stayed on 1.0, while the auto-upgrading workflow migrated.
+ autoUpgradeExecution.signal("doNextSignal", "conclude");
+ pinnedExecution.signal("doNextSignal", "conclude");
+ pinnedExecution2.signal("doNextSignal", "conclude");
+
+ // Wait for all workflows to complete
+ autoUpgradeExecution.getResult(Void.class);
+ pinnedExecution.getResult(Void.class);
+ pinnedExecution2.getResult(Void.class);
+
+ logger.info("All workflows completed");
+ }
+
+ private static void advanceWorkflows(
+ WorkflowStub autoUpgradeExecution, WorkflowStub pinnedExecution) {
+ // Signal both workflows a few times to drive them
+ for (int i = 0; i < 3; i++) {
+ autoUpgradeExecution.signal("doNextSignal", "do-activity");
+ pinnedExecution.signal("doNextSignal", "some-signal");
+ }
+ }
+
+ private static void waitForWorkerAndMakeCurrent(
+ WorkflowClient client, WorkflowServiceStubs service, String buildId)
+ throws InterruptedException {
+ WorkerDeploymentVersion targetVersion = new WorkerDeploymentVersion(DEPLOYMENT_NAME, buildId);
+
+ // Wait for the worker to appear
+ while (true) {
+ try {
+ DescribeWorkerDeploymentRequest describeRequest =
+ DescribeWorkerDeploymentRequest.newBuilder()
+ .setNamespace(client.getOptions().getNamespace())
+ .setDeploymentName(DEPLOYMENT_NAME)
+ .build();
+
+ DescribeWorkerDeploymentResponse response =
+ service.blockingStub().describeWorkerDeployment(describeRequest);
+
+ // Check if our version is present in the version summaries
+ boolean found =
+ response.getWorkerDeploymentInfo().getVersionSummariesList().stream()
+ .anyMatch(
+ versionSummary ->
+ targetVersion
+ .getDeploymentName()
+ .equals(versionSummary.getDeploymentVersion().getDeploymentName())
+ && targetVersion
+ .getBuildId()
+ .equals(versionSummary.getDeploymentVersion().getBuildId()));
+
+ if (found) {
+ break;
+ }
+ } catch (Exception ignored) {
+ System.out.println();
+ }
+ Thread.sleep(1000);
+ }
+
+ // Once the version is available, set it as current
+ SetWorkerDeploymentCurrentVersionRequest setRequest =
+ SetWorkerDeploymentCurrentVersionRequest.newBuilder()
+ .setNamespace(client.getOptions().getNamespace())
+ .setDeploymentName(DEPLOYMENT_NAME)
+ .setBuildId(targetVersion.getBuildId())
+ .build();
+
+ service.blockingStub().setWorkerDeploymentCurrentVersion(setRequest);
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java
new file mode 100644
index 000000000..42ff216e0
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1.java
@@ -0,0 +1,49 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.client.WorkflowClient;
+import io.temporal.common.WorkerDeploymentVersion;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerDeploymentOptions;
+import io.temporal.worker.WorkerFactory;
+import io.temporal.worker.WorkerOptions;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WorkerV1 {
+
+ private static final Logger logger = LoggerFactory.getLogger(WorkerV1.class);
+
+ public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+
+ WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "1.0");
+ WorkerDeploymentOptions deploymentOptions =
+ WorkerDeploymentOptions.newBuilder().setUseVersioning(true).setVersion(version).build();
+
+ WorkerOptions workerOptions =
+ WorkerOptions.newBuilder().setDeploymentOptions(deploymentOptions).build();
+
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+ Worker worker = factory.newWorker(Starter.TASK_QUEUE, workerOptions);
+
+ worker.registerWorkflowImplementationTypes(
+ AutoUpgradingWorkflowV1Impl.class, PinnedWorkflowV1Impl.class);
+ worker.registerActivitiesImplementations(new ActivitiesImpl());
+
+ logger.info("Starting worker v1 (build 1.0)");
+ factory.start();
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java
new file mode 100644
index 000000000..76ec8e278
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV1_1.java
@@ -0,0 +1,49 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.client.WorkflowClient;
+import io.temporal.common.WorkerDeploymentVersion;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerDeploymentOptions;
+import io.temporal.worker.WorkerFactory;
+import io.temporal.worker.WorkerOptions;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WorkerV1_1 {
+
+ private static final Logger logger = LoggerFactory.getLogger(WorkerV1_1.class);
+
+ public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+
+ WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "1.1");
+ WorkerDeploymentOptions deploymentOptions =
+ WorkerDeploymentOptions.newBuilder().setUseVersioning(true).setVersion(version).build();
+
+ WorkerOptions workerOptions =
+ WorkerOptions.newBuilder().setDeploymentOptions(deploymentOptions).build();
+
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+ Worker worker = factory.newWorker(Starter.TASK_QUEUE, workerOptions);
+
+ worker.registerWorkflowImplementationTypes(
+ AutoUpgradingWorkflowV1bImpl.class, PinnedWorkflowV1Impl.class);
+ worker.registerActivitiesImplementations(new ActivitiesImpl());
+
+ logger.info("Starting worker v1.1 (build 1.1)");
+ factory.start();
+ }
+}
diff --git a/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java
new file mode 100644
index 000000000..2c436a2dd
--- /dev/null
+++ b/core/src/main/java/io/temporal/samples/workerversioning/WorkerV2.java
@@ -0,0 +1,49 @@
+package io.temporal.samples.workerversioning;
+
+import io.temporal.client.WorkflowClient;
+import io.temporal.common.WorkerDeploymentVersion;
+import io.temporal.envconfig.ClientConfigProfile;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerDeploymentOptions;
+import io.temporal.worker.WorkerFactory;
+import io.temporal.worker.WorkerOptions;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WorkerV2 {
+
+ private static final Logger logger = LoggerFactory.getLogger(WorkerV2.class);
+
+ public static void main(String[] args) {
+ // Load configuration from environment and files
+ ClientConfigProfile profile;
+ try {
+ profile = ClientConfigProfile.load();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load client configuration", e);
+ }
+
+ WorkflowServiceStubs service =
+ WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
+ WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
+
+ WorkerDeploymentVersion version = new WorkerDeploymentVersion(Starter.DEPLOYMENT_NAME, "2.0");
+ WorkerDeploymentOptions deploymentOptions =
+ WorkerDeploymentOptions.newBuilder().setUseVersioning(true).setVersion(version).build();
+
+ WorkerOptions workerOptions =
+ WorkerOptions.newBuilder().setDeploymentOptions(deploymentOptions).build();
+
+ WorkerFactory factory = WorkerFactory.newInstance(client);
+ Worker worker = factory.newWorker(Starter.TASK_QUEUE, workerOptions);
+
+ worker.registerWorkflowImplementationTypes(
+ AutoUpgradingWorkflowV1bImpl.class, PinnedWorkflowV2Impl.class);
+ worker.registerActivitiesImplementations(new ActivitiesImpl());
+
+ logger.info("Starting worker v2 (build 2.0)");
+ factory.start();
+ }
+}
diff --git a/core/src/main/resources/config.toml b/core/src/main/resources/config.toml
new file mode 100644
index 000000000..81f07f786
--- /dev/null
+++ b/core/src/main/resources/config.toml
@@ -0,0 +1,40 @@
+# This is a sample configuration file for demonstrating Temporal's environment
+# configuration feature. It defines multiple profiles for different environments,
+# such as local development, production, and staging.
+
+# Default profile for local development
+[profile.default]
+address = "localhost:7233"
+namespace = "default"
+
+# Optional: Add custom gRPC headers
+[profile.default.grpc_meta]
+my-custom-header = "development-value"
+trace-id = "dev-trace-123"
+
+# Staging profile with inline certificate data
+[profile.staging]
+address = "localhost:9999"
+namespace = "staging"
+
+# An example production profile for Temporal Cloud
+[profile.prod]
+address = "your-namespace.a1b2c.tmprl.cloud:7233"
+namespace = "your-namespace"
+# Replace with your actual Temporal Cloud API key
+api_key = "your-api-key-here"
+
+# TLS configuration for production
+[profile.prod.tls]
+# TLS is auto-enabled when an API key is present, but you can configure it
+# explicitly.
+# disabled = false
+
+# Use certificate files for mTLS. Replace with actual paths.
+client_cert_path = "/etc/temporal/certs/client.pem"
+client_key_path = "/etc/temporal/certs/client.key"
+
+# Custom headers for production
+[profile.prod.grpc_meta]
+environment = "production"
+service-version = "v1.2.3"
\ No newline at end of file
diff --git a/core/src/test/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInitTest.java b/core/src/test/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInitTest.java
new file mode 100644
index 000000000..210967b28
--- /dev/null
+++ b/core/src/test/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInitTest.java
@@ -0,0 +1,76 @@
+package io.temporal.samples.hello;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import io.temporal.client.WorkflowFailedException;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.client.WorkflowStub;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkflowImplementationOptions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class HelloSignalWithStartAndWorkflowInitTest {
+ @RegisterExtension
+ public static final TestWorkflowExtension testWorkflowExtension =
+ TestWorkflowExtension.newBuilder()
+ .registerWorkflowImplementationTypes(
+ HelloSignalWithStartAndWorkflowInit.WithInitMyWorkflowImpl.class)
+ .registerWorkflowImplementationTypes(
+ WorkflowImplementationOptions.newBuilder()
+ .setFailWorkflowExceptionTypes(NullPointerException.class)
+ .build(),
+ HelloSignalWithStartAndWorkflowInit.WithoutInitMyWorkflowImpl.class)
+ .setActivityImplementations(
+ new HelloSignalWithStartAndWorkflowInit.MyGreetingActivitiesImpl())
+ .build();
+
+ @Test
+ public void testWithInit(TestWorkflowEnvironment testEnv, Worker worker) {
+ HelloSignalWithStartAndWorkflowInit.MyWorkflowWithInit withInitStub =
+ testEnv
+ .getWorkflowClient()
+ .newWorkflowStub(
+ HelloSignalWithStartAndWorkflowInit.MyWorkflowWithInit.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId("with-init")
+ .setTaskQueue(worker.getTaskQueue())
+ .build());
+ WorkflowStub.fromTyped(withInitStub)
+ .signalWithStart(
+ "addGreeting",
+ new Object[] {new HelloSignalWithStartAndWorkflowInit.Person("Michael", "Jordan", 55)},
+ new Object[] {new HelloSignalWithStartAndWorkflowInit.Person("John", "Stockton", 57)});
+ String result = WorkflowStub.fromTyped(withInitStub).getResult(String.class);
+ assertEquals("Hello Michael Jordan,Hello John Stockton", result);
+ }
+
+ @Test
+ public void testWithoutInit(TestWorkflowEnvironment testEnv, Worker worker) {
+ HelloSignalWithStartAndWorkflowInit.MyWorkflowNoInit noInitStub =
+ testEnv
+ .getWorkflowClient()
+ .newWorkflowStub(
+ HelloSignalWithStartAndWorkflowInit.MyWorkflowNoInit.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId("without-init")
+ .setTaskQueue(worker.getTaskQueue())
+ .build());
+ WorkflowStub.fromTyped(noInitStub)
+ .signalWithStart(
+ "addGreeting",
+ new Object[] {new HelloSignalWithStartAndWorkflowInit.Person("Michael", "Jordan", 55)},
+ new Object[] {new HelloSignalWithStartAndWorkflowInit.Person("John", "Stockton", 57)});
+ try {
+ WorkflowStub.fromTyped(noInitStub).getResult(String.class);
+ fail("Workflow execution should have failed");
+ } catch (Exception e) {
+ if (!(e instanceof WorkflowFailedException)) {
+ fail("Workflow execution should have failed with WorkflowFailedException");
+ }
+ }
+ }
+}
diff --git a/core/src/test/java/io/temporal/samples/hello/HelloUpdateAndCancellationTest.java b/core/src/test/java/io/temporal/samples/hello/HelloUpdateAndCancellationTest.java
new file mode 100644
index 000000000..b6eec1fec
--- /dev/null
+++ b/core/src/test/java/io/temporal/samples/hello/HelloUpdateAndCancellationTest.java
@@ -0,0 +1,210 @@
+package io.temporal.samples.hello;
+
+import io.temporal.activity.*;
+import io.temporal.api.enums.v1.WorkflowIdConflictPolicy;
+import io.temporal.client.*;
+import io.temporal.failure.ActivityFailure;
+import io.temporal.failure.CanceledFailure;
+import io.temporal.testing.TestWorkflowRule;
+import io.temporal.workflow.*;
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class HelloUpdateAndCancellationTest {
+ @Rule
+ public TestWorkflowRule testWorkflowRule =
+ TestWorkflowRule.newBuilder()
+ .setWorkflowTypes(TestWorkflowImpl.class)
+ .setActivityImplementations(new TestActivitiesImpl())
+ .build();
+
+ @Test
+ public void testUpdateAndWorkflowCancellation() {
+ // Start workflow with UpdateWithStart then cancel workflow before activity completes
+ TestWorkflow workflow =
+ testWorkflowRule
+ .getWorkflowClient()
+ .newWorkflowStub(
+ TestWorkflow.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId("test-workflow-cancel")
+ .setTaskQueue(testWorkflowRule.getTaskQueue())
+ .setWorkflowIdConflictPolicy(
+ WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING)
+ .build());
+
+ WorkflowUpdateHandle updateHandle =
+ WorkflowClient.startUpdateWithStart(
+ workflow::mileStoneCompleted,
+ UpdateOptions.newBuilder()
+ .setWaitForStage(WorkflowUpdateStage.ACCEPTED)
+ .build(),
+ new WithStartWorkflowOperation<>(workflow::execute));
+
+ testWorkflowRule
+ .getTestEnvironment()
+ .registerDelayedCallback(
+ Duration.ofSeconds(3),
+ () -> {
+ WorkflowStub.fromTyped(workflow).cancel("canceled by test");
+ });
+
+ String updateResult = updateHandle.getResult();
+ Assert.assertEquals("milestone canceled", updateResult);
+
+ try {
+ WorkflowStub.fromTyped(workflow).getResult(String.class);
+ Assert.fail("Workflow Execution should have been canceled");
+ } catch (WorkflowFailedException e) {
+ // Our workflow should have been canceled
+ Assert.assertEquals(CanceledFailure.class, e.getCause().getClass());
+ }
+ }
+
+ @Test
+ public void testUpdateAndActivityCancellation() {
+ // Start workflow with UpdateWithStart then cancel the activity only by sending signal to
+ // execution
+ TestWorkflow workflow =
+ testWorkflowRule
+ .getWorkflowClient()
+ .newWorkflowStub(
+ TestWorkflow.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId("test-activity-cancel")
+ .setTaskQueue(testWorkflowRule.getTaskQueue())
+ .setWorkflowIdConflictPolicy(
+ WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING)
+ .build());
+
+ WorkflowUpdateHandle updateHandle =
+ WorkflowClient.startUpdateWithStart(
+ workflow::mileStoneCompleted,
+ UpdateOptions.newBuilder()
+ .setWaitForStage(WorkflowUpdateStage.ACCEPTED)
+ .build(),
+ new WithStartWorkflowOperation<>(workflow::execute));
+
+ testWorkflowRule
+ .getTestEnvironment()
+ .registerDelayedCallback(
+ Duration.ofSeconds(3),
+ () -> {
+ WorkflowStub.fromTyped(workflow).signal("cancelActivity");
+ });
+
+ String updateResult = updateHandle.getResult();
+ Assert.assertEquals("milestone canceled", updateResult);
+
+ try {
+ WorkflowStub.fromTyped(workflow).getResult(String.class);
+ Assert.fail("Workflow Execution should have failed");
+ } catch (WorkflowFailedException e) {
+ // In this case we did not cancel workflow execution but we failed it by throwing
+ // ActivityFailure
+ Assert.assertEquals(ActivityFailure.class, e.getCause().getClass());
+ ActivityFailure af = (ActivityFailure) e.getCause();
+ // Since we canceled the activity still, the cause of ActivityFailure should be
+ // CanceledFailure
+ Assert.assertEquals(CanceledFailure.class, af.getCause().getClass());
+ }
+ }
+
+ @WorkflowInterface
+ public interface TestWorkflow {
+ @WorkflowMethod
+ String execute();
+
+ @UpdateMethod
+ String mileStoneCompleted();
+
+ @SignalMethod
+ void cancelActivity();
+ }
+
+ public static class TestWorkflowImpl implements TestWorkflow {
+ boolean milestoneDone, mileStoneCanceled;
+ CancellationScope scope;
+ TestActivities activities =
+ Workflow.newActivityStub(
+ TestActivities.class,
+ ActivityOptions.newBuilder()
+ .setHeartbeatTimeout(Duration.ofSeconds(3))
+ .setStartToCloseTimeout(Duration.ofSeconds(10))
+ .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED)
+ .build());
+
+ @Override
+ public String execute() {
+ scope =
+ Workflow.newCancellationScope(
+ () -> {
+ activities.runActivity();
+ });
+
+ try {
+ scope.run();
+ milestoneDone = true;
+ Workflow.await(Workflow::isEveryHandlerFinished);
+ return "workflow completed";
+ } catch (ActivityFailure e) {
+ if (e.getCause() instanceof CanceledFailure) {
+ CancellationScope detached =
+ Workflow.newDetachedCancellationScope(
+ () -> {
+ mileStoneCanceled = true;
+ Workflow.await(Workflow::isEveryHandlerFinished);
+ });
+ detached.run();
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public String mileStoneCompleted() {
+ Workflow.await(() -> milestoneDone || mileStoneCanceled);
+ // For sake of testing isEveryHandlerFinished block here for 2 seconds
+ Workflow.sleep(Duration.ofSeconds(2));
+ return milestoneDone ? "milestone completed" : "milestone canceled";
+ }
+
+ @Override
+ public void cancelActivity() {
+ if (scope != null) {
+ scope.cancel("test reason");
+ }
+ }
+ }
+
+ @ActivityInterface
+ public interface TestActivities {
+ void runActivity();
+ }
+
+ public static class TestActivitiesImpl implements TestActivities {
+
+ @Override
+ public void runActivity() {
+ ActivityExecutionContext context = Activity.getExecutionContext();
+ for (int i = 0; i < 9; i++) {
+ sleep(1);
+ try {
+ context.heartbeat(i);
+ } catch (ActivityCompletionException e) {
+ throw e;
+ }
+ }
+ }
+ }
+
+ private static void sleep(int seconds) {
+ try {
+ Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
+ } catch (InterruptedException e) {
+ }
+ }
+}
diff --git a/core/src/test/java/io/temporal/samples/interceptorreplaytest/InterceptorReplayTest.java b/core/src/test/java/io/temporal/samples/interceptorreplaytest/InterceptorReplayTest.java
new file mode 100644
index 000000000..97ea42ec8
--- /dev/null
+++ b/core/src/test/java/io/temporal/samples/interceptorreplaytest/InterceptorReplayTest.java
@@ -0,0 +1,191 @@
+package io.temporal.samples.interceptorreplaytest;
+
+import static org.junit.Assert.fail;
+
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityOptions;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.common.WorkflowExecutionHistory;
+import io.temporal.common.interceptors.*;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import io.temporal.testing.WorkflowReplayer;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerFactoryOptions;
+import io.temporal.workflow.Workflow;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+import java.time.Duration;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class InterceptorReplayTest {
+ @RegisterExtension
+ public static final TestWorkflowExtension testWorkflowExtension =
+ TestWorkflowExtension.newBuilder()
+ // Register workflow and activity impls
+ .registerWorkflowImplementationTypes(TestWorkflowImpl.class)
+ .setActivityImplementations(new TestActivitiesImpl())
+ // Register worker interceptor
+ .setWorkerFactoryOptions(
+ WorkerFactoryOptions.newBuilder()
+ .setWorkerInterceptors(new TestWorkerInterceptor())
+ .build())
+ .setDoNotStart(true)
+ .build();
+
+ @Test
+ public void testReplayWithInterceptors(TestWorkflowEnvironment testEnv, Worker worker) {
+ // Run our test workflow. We need to set workflow id so can get history after
+ testEnv.start();
+ TestWorkflow workflow =
+ testEnv
+ .getWorkflowClient()
+ .newWorkflowStub(
+ TestWorkflow.class,
+ WorkflowOptions.newBuilder()
+ .setWorkflowId("test-workflow")
+ .setTaskQueue(worker.getTaskQueue())
+ .build());
+ workflow.execute();
+
+ // Replay execution with history of just executed
+ WorkflowExecutionHistory eventHistory =
+ testEnv.getWorkflowClient().fetchHistory("test-workflow");
+
+ try {
+ WorkflowReplayer.replayWorkflowExecution(eventHistory, worker);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ testEnv.shutdown();
+
+ // Try replaying execution with test env where we dont have interceptors registered
+ TestWorkflowEnvironment testEnv2 = TestWorkflowEnvironment.newInstance();
+ Worker testEnv2Worker = testEnv2.newWorker("test-taskqueue");
+ testEnv2Worker.registerWorkflowImplementationTypes(TestWorkflowImpl.class);
+ testEnv2Worker.registerActivitiesImplementations(new TestActivitiesImpl());
+
+ testEnv2.start();
+
+ // Replay should fail with worker that does not have interceptor registered
+ try {
+ WorkflowReplayer.replayWorkflowExecution(eventHistory, testEnv2Worker);
+ fail("This should have failed");
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+
+ // But it should be fine with worker that does
+ try {
+ WorkflowReplayer.replayWorkflowExecution(eventHistory, worker);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ testEnv2.shutdown();
+ }
+
+ // Test workflow and activities
+ @WorkflowInterface
+ public interface TestWorkflow {
+ @WorkflowMethod
+ void execute();
+ }
+
+ public static class TestWorkflowImpl implements TestWorkflow {
+
+ TestActivities activities =
+ Workflow.newActivityStub(
+ TestActivities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
+
+ @Override
+ public void execute() {
+ activities.activityOne();
+ }
+ }
+
+ @ActivityInterface
+ public interface TestActivities {
+ void activityOne();
+
+ void activityTwo();
+
+ void activityThree();
+ }
+
+ public static class TestActivitiesImpl implements TestActivities {
+ @Override
+ public void activityOne() {
+ System.out.println("Activities one done");
+ }
+
+ @Override
+ public void activityTwo() {
+ System.out.println("Activities two done");
+ }
+
+ @Override
+ public void activityThree() {
+ System.out.println("Activities three done");
+ }
+ }
+
+ // Test worker and workflow interceptors
+ public static class TestWorkerInterceptor extends WorkerInterceptorBase {
+ @Override
+ public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) {
+ return new TestWorkflowInboundCallsInterceptor(next);
+ }
+ }
+
+ public static class TestWorkflowInboundCallsInterceptor
+ extends WorkflowInboundCallsInterceptorBase {
+ TestActivities activities =
+ Workflow.newActivityStub(
+ TestActivities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
+
+ public TestWorkflowInboundCallsInterceptor(WorkflowInboundCallsInterceptor next) {
+ super(next);
+ }
+
+ @Override
+ public void init(WorkflowOutboundCallsInterceptor outboundCalls) {
+ super.init(new TestWorkflowOutboundCallsInterceptor(outboundCalls));
+ }
+
+ @Override
+ public WorkflowOutput execute(WorkflowInput input) {
+ WorkflowOutput output = super.execute(input);
+ // Run activity three before completing execution
+ activities.activityThree();
+ return output;
+ }
+ }
+
+ public static class TestWorkflowOutboundCallsInterceptor
+ extends WorkflowOutboundCallsInterceptorBase {
+ TestActivities activities =
+ Workflow.newActivityStub(
+ TestActivities.class,
+ ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
+
+ public TestWorkflowOutboundCallsInterceptor(WorkflowOutboundCallsInterceptor next) {
+ super(next);
+ }
+
+ @Override
+ public ActivityOutput executeActivity(ActivityInput input) {
+ ActivityOutput output = super.executeActivity(input);
+
+ // we only want to intercept ActivityOne here
+ if (input.getActivityName().equals("ActivityOne")) {
+ activities.activityTwo();
+ }
+
+ return output;
+ }
+ }
+}
diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java
new file mode 100644
index 000000000..2ba042308
--- /dev/null
+++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java
@@ -0,0 +1,82 @@
+package io.temporal.samples.nexus.caller;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.*;
+
+import io.temporal.samples.nexus.handler.EchoClient;
+import io.temporal.samples.nexus.handler.HelloHandlerWorkflow;
+import io.temporal.samples.nexus.handler.SampleNexusServiceImpl;
+import io.temporal.samples.nexus.service.SampleNexusService;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import io.temporal.worker.Worker;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+// This is an example of how to unit test Nexus services in JUnit5. The handlers are mocked,
+// so that the caller classes interact with the mocks and not the handler classes themselves.
+
+// @@@SNIPSTART java-nexus-sample-junit5-mock
+public class CallerWorkflowJunit5MockTest {
+
+ // Sync Nexus operations run inline in the handler thread — there is no backing workflow to
+ // register a factory for. To mock one, inject a mock dependency into the service implementation.
+ private static final EchoClient mockEchoClient = mock(EchoClient.class);
+
+ @RegisterExtension
+ public static final TestWorkflowExtension testWorkflowExtension =
+ TestWorkflowExtension.newBuilder()
+ // If a Nexus service is registered as part of the test as in the following line of code,
+ // the TestWorkflowExtension will, by default, automatically create a Nexus service
+ // endpoint and workflows registered as part of the TestWorkflowExtension will
+ // automatically inherit the endpoint if none is set.
+ .setNexusServiceImplementation(new SampleNexusServiceImpl(mockEchoClient))
+ // The Echo Nexus handler service just makes a call to a class, so no extra setup is
+ // needed. But the Hello Nexus service needs a worker for both the caller and handler
+ // in order to run, and the Echo Nexus caller service needs a worker.
+ //
+ // registerWorkflowImplementationTypes will take the classes given and create workers for
+ // them, enabling workflows to run.
+ .registerWorkflowImplementationTypes(
+ HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class)
+ .setDoNotStart(true)
+ .build();
+
+ @Test
+ public void testHelloWorkflow(
+ TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) {
+ // Workflows started by a Nexus service can be mocked just like any other workflow
+ worker.registerWorkflowImplementationFactory(
+ HelloHandlerWorkflow.class,
+ () -> {
+ HelloHandlerWorkflow mockHandler = mock(HelloHandlerWorkflow.class);
+ when(mockHandler.hello(any()))
+ .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World 👋"));
+ return mockHandler;
+ });
+ testEnv.start();
+
+ // Execute a workflow waiting for it to complete.
+ String greeting = workflow.hello("World", SampleNexusService.Language.EN);
+ assertEquals("Hello Mock World 👋", greeting);
+
+ testEnv.shutdown();
+ }
+
+ @Test
+ public void testEchoWorkflow(
+ TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) {
+ // Sync Nexus operations run inline in the handler thread — there is no backing workflow to
+ // register a factory for. Instead, stub the injected EchoClient dependency directly.
+ when(mockEchoClient.echo(any())).thenReturn(new SampleNexusService.EchoOutput("mocked echo"));
+ testEnv.start();
+
+ // Execute a workflow waiting for it to complete.
+ String greeting = workflow.echo("Hello");
+ assertEquals("mocked echo", greeting);
+
+ testEnv.shutdown();
+ }
+}
+
+// @@@SNIPEND
diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java
new file mode 100644
index 000000000..3da730c14
--- /dev/null
+++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java
@@ -0,0 +1,58 @@
+package io.temporal.samples.nexus.caller;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import io.temporal.samples.nexus.handler.HelloHandlerWorkflowImpl;
+import io.temporal.samples.nexus.handler.SampleNexusServiceImpl;
+import io.temporal.samples.nexus.service.SampleNexusService;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import io.temporal.worker.Worker;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+// This is an example of how to unit test Nexus services in JUnit5. The handlers are not mocked,
+// but are actually called by the testing framework by the caller classes.
+
+public class CallerWorkflowJunit5Test {
+
+ @RegisterExtension
+ public static final TestWorkflowExtension testWorkflowExtension =
+ TestWorkflowExtension.newBuilder()
+ // If a Nexus service is registered as part of the test as in the following line of code,
+ // the TestWorkflowExtension will, by default, automatically create a Nexus service
+ // endpoint and workflows registered as part of the TestWorkflowExtension will
+ // automatically inherit the endpoint if none is set.
+ .setNexusServiceImplementation(new SampleNexusServiceImpl())
+ // The Echo Nexus handler service just makes a call to a class, so no extra setup is
+ // needed. But the Hello Nexus service needs a worker for both the caller and handler
+ // in order to run, and the Echo Nexus caller service needs a worker.
+ //
+ // registerWorkflowImplementationTypes will take the classes given and create workers for
+ // them, enabling workflows to run.
+ .registerWorkflowImplementationTypes(
+ HelloCallerWorkflowImpl.class,
+ HelloHandlerWorkflowImpl.class,
+ EchoCallerWorkflowImpl.class)
+ // The workflow will start before each test, and will shut down after each test.
+ // See CallerWorkflowTest for an example of how to control this differently if needed.
+ .build();
+
+ // The TestWorkflowExtension extension in the Temporal testing library creates the
+ // arguments to the test cases and initializes them from the extension setup call above.
+ @Test
+ public void testHelloWorkflow(
+ TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) {
+ // Execute a workflow waiting for it to complete.
+ String greeting = workflow.hello("World", SampleNexusService.Language.EN);
+ assertEquals("Hello World 👋", greeting);
+ }
+
+ @Test
+ public void testEchoWorkflow(
+ TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) {
+ // Execute a workflow waiting for it to complete.
+ String greeting = workflow.echo("Hello");
+ assertEquals("Hello", greeting);
+ }
+}
diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java
new file mode 100644
index 000000000..d6b793ffe
--- /dev/null
+++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java
@@ -0,0 +1,95 @@
+package io.temporal.samples.nexus.caller;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import io.temporal.client.WorkflowOptions;
+import io.temporal.samples.nexus.handler.EchoClient;
+import io.temporal.samples.nexus.handler.HelloHandlerWorkflow;
+import io.temporal.samples.nexus.handler.SampleNexusServiceImpl;
+import io.temporal.samples.nexus.service.SampleNexusService;
+import io.temporal.testing.TestWorkflowRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+// This is an example of how to unit test Nexus services in JUnit4. The handlers are mocked,
+// so that the caller classes interact with the mocks and not the handler classes themselves.
+
+// @@@SNIPSTART java-nexus-sample-junit4-mock
+public class CallerWorkflowMockTest {
+
+ // Inject a mock EchoClient so sync Nexus operations can be stubbed per test.
+ // JUnit 4 creates a new test class instance per test method, so this mock is fresh each time.
+ private final EchoClient mockEchoClient = mock(EchoClient.class);
+
+ @Rule
+ public TestWorkflowRule testWorkflowRule =
+ TestWorkflowRule.newBuilder()
+ // If a Nexus service is registered as part of the test as in the following line of code,
+ // the TestWorkflowRule will, by default, automatically create a Nexus service endpoint
+ // and workflows registered as part of the TestWorkflowRule
+ // will automatically inherit the endpoint if none is set.
+ .setNexusServiceImplementation(new SampleNexusServiceImpl(mockEchoClient))
+ // The Echo Nexus handler service just makes a call to a class, so no extra setup is
+ // needed. But the Hello Nexus service needs a worker for both the caller and handler
+ // in order to run.
+ // setWorkflowTypes will take the classes given and create workers for them, enabling
+ // workflows to run. This creates caller workflows, the handler workflows
+ // will be mocked in the test methods.
+ .setWorkflowTypes(HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class)
+ // Disable automatic worker startup as we are going to register some workflows manually
+ // per test
+ .setDoNotStart(true)
+ .build();
+
+ @Test
+ public void testHelloWorkflow() {
+ testWorkflowRule
+ .getWorker()
+ // Workflows started by a Nexus service can be mocked just like any other workflow
+ .registerWorkflowImplementationFactory(
+ HelloHandlerWorkflow.class,
+ () -> {
+ HelloHandlerWorkflow wf = mock(HelloHandlerWorkflow.class);
+ when(wf.hello(any()))
+ .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World 👋"));
+ return wf;
+ });
+ testWorkflowRule.getTestEnvironment().start();
+
+ // Now create the caller workflow
+ HelloCallerWorkflow workflow =
+ testWorkflowRule
+ .getWorkflowClient()
+ .newWorkflowStub(
+ HelloCallerWorkflow.class,
+ WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
+ String greeting = workflow.hello("World", SampleNexusService.Language.EN);
+ assertEquals("Hello Mock World 👋", greeting);
+
+ testWorkflowRule.getTestEnvironment().shutdown();
+ }
+
+ @Test
+ public void testEchoWorkflow() {
+ // Sync Nexus operations run inline in the handler thread — there is no backing workflow to
+ // register a factory for. Instead, stub the injected EchoCient dependency directly.
+ when(mockEchoClient.echo(any())).thenReturn(new SampleNexusService.EchoOutput("mocked echo"));
+ testWorkflowRule.getTestEnvironment().start();
+
+ EchoCallerWorkflow workflow =
+ testWorkflowRule
+ .getWorkflowClient()
+ .newWorkflowStub(
+ EchoCallerWorkflow.class,
+ WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
+ String greeting = workflow.echo("Hello");
+ assertEquals("mocked echo", greeting);
+
+ testWorkflowRule.getTestEnvironment().shutdown();
+ }
+}
+
+// @@@SNIPEND
diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java
index 2d3a6e42a..682995e61 100644
--- a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java
+++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java
@@ -1,14 +1,11 @@
package io.temporal.samples.nexus.caller;
import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import io.temporal.client.WorkflowOptions;
-import io.temporal.samples.nexus.handler.HelloHandlerWorkflow;
-import io.temporal.samples.nexus.handler.NexusServiceImpl;
-import io.temporal.samples.nexus.service.NexusService;
+import io.temporal.samples.nexus.handler.HelloHandlerWorkflowImpl;
+import io.temporal.samples.nexus.handler.SampleNexusServiceImpl;
+import io.temporal.samples.nexus.service.SampleNexusService;
import io.temporal.testing.TestWorkflowRule;
import io.temporal.worker.WorkflowImplementationOptions;
import io.temporal.workflow.NexusServiceOptions;
@@ -16,16 +13,27 @@
import org.junit.Rule;
import org.junit.Test;
+// This is an example of how to unit test Nexus services in JUnit4. The handlers are not mocked,
+// but are actually called by the testing framework by the caller classes.
+
public class CallerWorkflowTest {
@Rule
public TestWorkflowRule testWorkflowRule =
TestWorkflowRule.newBuilder()
- // If a Nexus service is registered as part of the test, the TestWorkflowRule will ,by
- // default, automatically create a Nexus service endpoint and workflows registered as part
- // of the TestWorkflowRule will automatically inherit the endpoint if none is set.
- .setNexusServiceImplementation(new NexusServiceImpl())
- .setWorkflowTypes(HelloCallerWorkflowImpl.class)
+ // If a Nexus service is registered as part of the test as in the following line of code,
+ // the TestWorkflowRule will, by default, automatically create a Nexus service endpoint
+ // and workflows registered as part of the TestWorkflowRule
+ // will automatically inherit the endpoint if none is set.
+ .setNexusServiceImplementation(new SampleNexusServiceImpl())
+ // The Echo Nexus handler service just makes a call to a class, so no extra setup is
+ // needed. But the Hello Nexus service needs a worker for both the caller and handler
+ // in order to run.
+ // setWorkflowTypes will take the classes given and create workers for them, enabling
+ // workflows to run. This is not adding an EchoCallerWorkflow though -
+ // see the testEchoWorkflow test method below for an example of an alternate way
+ // to supply a worker that gives you more flexibility if needed.
+ .setWorkflowTypes(HelloCallerWorkflowImpl.class, HelloHandlerWorkflowImpl.class)
// Disable automatic worker startup as we are going to register some workflows manually
// per test
.setDoNotStart(true)
@@ -33,16 +41,6 @@ public class CallerWorkflowTest {
@Test
public void testHelloWorkflow() {
- testWorkflowRule
- .getWorker()
- // Workflows started by a Nexus service can be mocked just like any other workflow
- .registerWorkflowImplementationFactory(
- HelloHandlerWorkflow.class,
- () -> {
- HelloHandlerWorkflow wf = mock(HelloHandlerWorkflow.class);
- when(wf.hello(any())).thenReturn(new NexusService.HelloOutput("Hello World 👋"));
- return wf;
- });
testWorkflowRule.getTestEnvironment().start();
HelloCallerWorkflow workflow =
@@ -51,7 +49,7 @@ public void testHelloWorkflow() {
.newWorkflowStub(
HelloCallerWorkflow.class,
WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
- String greeting = workflow.hello("World", NexusService.Language.EN);
+ String greeting = workflow.hello("World", SampleNexusService.Language.EN);
assertEquals("Hello World 👋", greeting);
testWorkflowRule.getTestEnvironment().shutdown();
@@ -61,15 +59,20 @@ public void testHelloWorkflow() {
public void testEchoWorkflow() {
// If Workflows are registered later than the endpoint can be set manually
// either by setting the endpoint in the NexusServiceOptions in the Workflow implementation or
- // by setting the NexusServiceOptions on the WorkflowImplementationOptions when registering the
- // Workflow.
+ // by setting the NexusServiceOptions on the WorkflowImplementationOptions when registering
+ // the Workflow. To demonstrate, this is creating the Nexus service for Echo,
+ // and registering a EchoCallerWorkflowImpl worker.
+ //
+ // It is much simpler to use the setWorkflowTypes in the rule definition above - and as
+ // this isn't easily do-able in JUnit5 (the nexus endpoint isn't exposed) should be
+ // used with caution.
testWorkflowRule
.getWorker()
.registerWorkflowImplementationTypes(
WorkflowImplementationOptions.newBuilder()
.setNexusServiceOptions(
Collections.singletonMap(
- "NexusService",
+ "SampleNexusService",
NexusServiceOptions.newBuilder()
.setEndpoint(testWorkflowRule.getNexusEndpoint().getSpec().getName())
.build()))
diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java
new file mode 100644
index 000000000..0b03b2d64
--- /dev/null
+++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java
@@ -0,0 +1,109 @@
+package io.temporal.samples.nexus.caller;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import io.nexusrpc.handler.OperationHandler;
+import io.nexusrpc.handler.OperationImpl;
+import io.nexusrpc.handler.ServiceImpl;
+import io.temporal.samples.nexus.service.SampleNexusService;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import io.temporal.worker.Worker;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+// This unit test example shows how to mock the Nexus service itself in JUnit4.
+// This is the path to take when you don't have access to the service implementation so
+// cannot mock it. Since the SampleNexusService itself is mocked,
+// no handlers need to be set up or mocked.
+
+// @@@SNIPSTART java-nexus-service-sample-junit5-mock
+public class NexusServiceJunit5Test {
+
+ private final SampleNexusService mockNexusService = mock(SampleNexusService.class);
+
+ /**
+ * A test-only Nexus service implementation that delegates to the Mockito mock defined above. Both
+ * operations are implemented as synchronous handlers that forward calls to the mock, allowing
+ * full control over return values and verification of inputs.
+ */
+ @ServiceImpl(service = SampleNexusService.class)
+ public class TestNexusServiceImpl {
+ @OperationImpl
+ @SuppressWarnings("DirectInvocationOnMock")
+ public OperationHandler echo() {
+ return OperationHandler.sync((ctx, details, input) -> mockNexusService.echo(input));
+ }
+
+ @OperationImpl
+ @SuppressWarnings("DirectInvocationOnMock")
+ public OperationHandler hello() {
+ return OperationHandler.sync((ctx, details, input) -> mockNexusService.hello(input));
+ }
+ }
+
+ // Using OperationHandler.sync for both operations bypasses the need for a backing workflow,
+ // returning results inline just like a synchronous call.
+ //
+ // Note that the Mocks need to be done before the extension
+ // is defined, as creating the rule will fail if either call is still null.
+
+ @RegisterExtension
+ public final TestWorkflowExtension testWorkflowExtension =
+ TestWorkflowExtension.newBuilder()
+ // If a Nexus service is registered as part of the test as in the following line of code,
+ // the TestWorkflowExtension will, by default, automatically create a Nexus service
+ // endpoint and workflows registered as part of the TestWorkflowExtension will
+ // automatically inherit the endpoint if none is set.
+ .setNexusServiceImplementation(new TestNexusServiceImpl())
+ // The Echo Nexus handler service just makes a call to a class, so no extra setup is
+ // needed. But the Hello Nexus service needs a worker for both the caller and handler
+ // in order to run, and the Echo Nexus caller service needs a worker.
+ //
+ // registerWorkflowImplementationTypes will take the classes given and create workers for
+ // them, enabling workflows to run.
+ // Since both operations are mocked with OperationHandler.sync, no backing workflow is
+ // needed for hello — only the caller workflow types need to be registered.
+ .registerWorkflowImplementationTypes(
+ HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class)
+ // The workflow will start before each test, and will shut down after each test.
+ // See CallerWorkflowTest for an example of how to control this differently if needed.
+ .build();
+
+ // The TestWorkflowExtension extension in the Temporal testing library creates the
+ // arguments to the test cases and initializes them from the extension setup call above.
+ @Test
+ public void testHelloWorkflow(
+ TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) {
+
+ // Set the mock value to return
+ when(mockNexusService.hello(any()))
+ .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World 👋"));
+
+ // Execute a workflow waiting for it to complete.
+ String greeting = workflow.hello("World", SampleNexusService.Language.EN);
+ assertEquals("Hello Mock World 👋", greeting);
+ }
+
+ @Test
+ public void testEchoWorkflow(
+ TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) {
+ when(mockNexusService.echo(any()))
+ .thenReturn(new SampleNexusService.EchoOutput("echo response"));
+
+ // Execute a workflow waiting for it to complete.
+ String greeting = workflow.echo("echo input");
+ assertEquals("echo response", greeting);
+
+ // Verify the echo operation was called exactly once and no other operations were invoked
+ verify(mockNexusService, times(1)).echo(any());
+ // Verify the Nexus service was called with the correct input
+ verify(mockNexusService).echo(argThat(input -> "echo input".equals(input.getMessage())));
+
+ verifyNoMoreInteractions(mockNexusService);
+ }
+}
+
+// @@@SNIPEND
diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java
new file mode 100644
index 000000000..8dafc6388
--- /dev/null
+++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java
@@ -0,0 +1,108 @@
+package io.temporal.samples.nexus.caller;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import io.nexusrpc.handler.OperationHandler;
+import io.nexusrpc.handler.OperationImpl;
+import io.nexusrpc.handler.ServiceImpl;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.samples.nexus.service.SampleNexusService;
+import io.temporal.testing.TestWorkflowRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+// This unit test example shows how to mock the Nexus service itself in JUnit4.
+// This is the path to take when you don't have access to the service implementation so
+// cannot mock it. Since the SampleNexusService itself is mocked,
+// no handlers need to be set up or mocked.
+
+// @@@SNIPSTART java-nexus-service-sample-junit4-mock
+public class NexusServiceMockTest {
+
+ private final SampleNexusService mockNexusService = mock(SampleNexusService.class);
+
+ /**
+ * A test-only Nexus service implementation that delegates to the Mockito mock defined above. Both
+ * operations are implemented as synchronous handlers that forward calls to the mock, allowing
+ * full control over return values and verification of inputs.
+ */
+ @ServiceImpl(service = SampleNexusService.class)
+ public class TestNexusServiceImpl {
+ @OperationImpl
+ @SuppressWarnings("DirectInvocationOnMock")
+ public OperationHandler echo() {
+ return OperationHandler.sync((ctx, details, input) -> mockNexusService.echo(input));
+ }
+
+ @OperationImpl
+ @SuppressWarnings("DirectInvocationOnMock")
+ public OperationHandler hello() {
+ return OperationHandler.sync((ctx, details, input) -> mockNexusService.hello(input));
+ }
+ }
+
+ // Using OperationHandler.sync for both operations bypasses the need for a backing workflow,
+ // returning results inline just like a synchronous call.
+ //
+ // Note that the Mocks need to be done before the rule
+ // is defined, as creating the rule will fail if either call is still null.
+
+ @Rule
+ public TestWorkflowRule testWorkflowRule =
+ TestWorkflowRule.newBuilder()
+ .setNexusServiceImplementation(new TestNexusServiceImpl())
+ .setWorkflowTypes(EchoCallerWorkflowImpl.class, HelloCallerWorkflowImpl.class)
+ .build();
+
+ @Test
+ public void testHelloCallerWithMockedService() {
+ when(mockNexusService.hello(any()))
+ .thenReturn(new SampleNexusService.HelloOutput("Bonjour World"));
+
+ HelloCallerWorkflow workflow =
+ testWorkflowRule
+ .getWorkflowClient()
+ .newWorkflowStub(
+ HelloCallerWorkflow.class,
+ WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
+
+ String result = workflow.hello("World", SampleNexusService.Language.FR);
+ assertEquals("Bonjour World", result);
+
+ // Verify the Nexus service was called with the correct name and language
+ verify(mockNexusService)
+ .hello(
+ argThat(
+ input ->
+ "World".equals(input.getName())
+ && SampleNexusService.Language.FR == input.getLanguage()));
+ }
+
+ @Test
+ public void testEchoCallerWithMockedService() {
+ when(mockNexusService.echo(any()))
+ .thenReturn(new SampleNexusService.EchoOutput("echo response"));
+
+ EchoCallerWorkflow workflow =
+ testWorkflowRule
+ .getWorkflowClient()
+ .newWorkflowStub(
+ EchoCallerWorkflow.class,
+ WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
+
+ String echoOutput = workflow.echo("echo input");
+
+ assertEquals("echo response", echoOutput);
+
+ // Verify the echo operation was called exactly once and no other operations were invoked
+ verify(mockNexusService, times(1)).echo(any());
+ // Verify the Nexus service was called with the correct input
+ verify(mockNexusService).echo(argThat(input -> "echo input".equals(input.getMessage())));
+
+ verifyNoMoreInteractions(mockNexusService);
+ }
+}
+
+// @@@SNIPEND
diff --git a/springboot/build.gradle b/springboot/build.gradle
index 7120304e9..aa632df51 100644
--- a/springboot/build.gradle
+++ b/springboot/build.gradle
@@ -9,6 +9,9 @@ dependencies {
// we set this as impl depends to use embedded kafka in samples not just tests
implementation "org.springframework.kafka:spring-kafka-test"
implementation "io.temporal:temporal-spring-boot-starter:$javaSDKVersion"
+
+ // Environment configuration
+ implementation "io.temporal:temporal-envconfig:$javaSDKVersion"
implementation "org.apache.camel.springboot:camel-spring-boot-starter:$camelVersion"
implementation "org.apache.camel.springboot:camel-servlet-starter:$camelVersion"
runtimeOnly "io.micrometer:micrometer-registry-prometheus"
diff --git a/springboot/src/test/resources/application.yaml b/springboot/src/test/resources/application.yaml
index b81a11934..017d28f90 100644
--- a/springboot/src/test/resources/application.yaml
+++ b/springboot/src/test/resources/application.yaml
@@ -15,6 +15,7 @@ spring:
# enable test server for testing
test-server:
enabled: true
+ ignore-duplicate-definitions: true
# data source config for tests that need it
datasource:
url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;DB_CLOSE_ON_EXIT=FALSE;