Note that a workflow implementation must always be public for the Temporal library to be able
9 | * to create its instances.
10 | */
11 | public class ChildWorkflowImpl implements ChildWorkflow {
12 |
13 | @Override
14 | public String composeGreeting(String greeting, String name) {
15 |
16 | // Sleep for 2 seconds to ensure the child completes after the parent.
17 | Workflow.sleep(2000);
18 |
19 | return greeting + " " + name + "!";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/asyncuntypedchild/ParentWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.asyncuntypedchild;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | /**
7 | * Define the parent workflow interface. It must contain one method annotated with @WorkflowMethod
8 | *
9 | * @see WorkflowInterface
10 | * @see WorkflowMethod
11 | */
12 | @WorkflowInterface
13 | public interface ParentWorkflow {
14 |
15 | /**
16 | * Define the parent workflow method. This method is executed when the workflow is started. The
17 | * workflow completes when the workflow method finishes execution.
18 | */
19 | @WorkflowMethod
20 | String getGreeting(String name);
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/asyncuntypedchild/README.md:
--------------------------------------------------------------------------------
1 | # Async Child Workflow execution
2 |
3 | The sample demonstrates shows how to invoke an Untyped Child Workflow asynchronously.
4 | The Child Workflow continues running for some time after the Parent Workflow completes.
5 |
6 | ```bash
7 | ./gradlew -q execute -PmainClass=io.temporal.samples.asyncuntypedchild.Starter
8 | ```
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchStarter.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | import static io.temporal.samples.batch.heartbeatingactivity.HeartbeatingActivityBatchWorker.TASK_QUEUE;
4 |
5 | import io.temporal.api.common.v1.WorkflowExecution;
6 | import io.temporal.client.WorkflowClient;
7 | import io.temporal.client.WorkflowOptions;
8 | import io.temporal.serviceclient.WorkflowServiceStubs;
9 |
10 | /** Starts a single execution of HeartbeatingActivityBatchWorkflow. */
11 | public class HeartbeatingActivityBatchStarter {
12 |
13 | public static void main(String[] args) {
14 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
15 | WorkflowClient workflowClient = WorkflowClient.newInstance(service);
16 | WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build();
17 | HeartbeatingActivityBatchWorkflow batchWorkflow =
18 | workflowClient.newWorkflowStub(HeartbeatingActivityBatchWorkflow.class, options);
19 | WorkflowExecution execution = WorkflowClient.start(batchWorkflow::processBatch);
20 | System.out.println(
21 | "Started batch workflow. WorkflowId="
22 | + execution.getWorkflowId()
23 | + ", RunId="
24 | + execution.getRunId());
25 | System.exit(0);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 |
8 | /**
9 | * A worker process that hosts implementations of HeartbeatingActivityBatchWorkflow and
10 | * RecordProcessorActivity.
11 | */
12 | public final class HeartbeatingActivityBatchWorker {
13 |
14 | static final String TASK_QUEUE = "HeartbeatingActivityBatch";
15 |
16 | public static void main(String[] args) {
17 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
18 | WorkflowClient client = WorkflowClient.newInstance(service);
19 |
20 | WorkerFactory factory = WorkerFactory.newInstance(client);
21 | Worker worker = factory.newWorker(TASK_QUEUE);
22 |
23 | worker.registerWorkflowImplementationTypes(HeartbeatingActivityBatchWorkflowImpl.class);
24 |
25 | worker.registerActivitiesImplementations(
26 | new RecordProcessorActivityImpl(new RecordLoaderImpl(), new RecordProcessorImpl()));
27 | factory.start();
28 | System.out.println("Worker started for task queue: " + TASK_QUEUE);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/HeartbeatingActivityBatchWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface HeartbeatingActivityBatchWorkflow {
8 |
9 | /**
10 | * Processes the batch of records.
11 | *
12 | * @return total number of processed records.
13 | */
14 | @WorkflowMethod
15 | int processBatch();
16 | }
17 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/README.md:
--------------------------------------------------------------------------------
1 | A sample implementation of processing a batch by an Activity.
2 |
3 | An Activity can run as long as needed.
4 | It reports that it is still alive through Heartbeat.
5 |
6 | If the Worker is restarted, the Activity is retried after the Heartbeat Timeout.
7 |
8 | Temporal allows store data in Heartbeat _details_.
9 | These details are available to the next Activity attempt.
10 | The progress of the record processing is stored in the details to avoid reprocessing records from the beginning on failures.
11 |
12 | #### Running the Iterator Batch Sample
13 |
14 | The sample has two executables. Execute each command in a separate terminal window.
15 |
16 | The first command runs the Worker that hosts the Workflow and Activity Executions. Restart the worker while the batch is
17 | executing to see how activity timeout and retry work.
18 |
19 | ```bash
20 | ./gradlew -q execute -PmainClass=io.temporal.samples.batch.heartbeatingactivity.HeartbeatingActivityBatchWorker
21 | ```
22 |
23 | The second command start the Workflow Execution. Each time the command runs, it starts a new Workflow Execution.
24 |
25 | ```bash
26 | ./gradlew -q execute -PmainClass=io.temporal.samples.batch.heartbeatingactivity.HeartbeatingActivityBatchStarter
27 | ```
28 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoader.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | import java.util.Optional;
4 |
5 | /**
6 | * Helper class that is used to iterate over a list of records.
7 | *
8 | *
A specific implementation depends on a use case. For example, it can execute an SQL DB query
9 | * or read a comma delimited file. More complex use cases would need passing a different type of
10 | * offset parameter.
11 | */
12 | public interface RecordLoader {
13 |
14 | /**
15 | * Returns the next record.
16 | *
17 | * @param offset offset of the next record.
18 | * @return Record at the offset. Empty optional if offset exceeds the dataset size.
19 | */
20 | Optional getRecord(int offset);
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordLoaderImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | import java.util.Optional;
4 |
5 | /** Fake implementation of RecordLoader. */
6 | public final class RecordLoaderImpl implements RecordLoader {
7 |
8 | static final int RECORD_COUNT = 1000;
9 |
10 | @Override
11 | public Optional getRecord(int offset) {
12 | if (offset >= RECORD_COUNT) {
13 | return Optional.empty();
14 | }
15 | return Optional.of(new SingleRecord(offset));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessor.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | /** A helper class that implements record processing. */
4 | public interface RecordProcessor {
5 |
6 | /**
7 | * Processes a single record.
8 | *
9 | * @param record record to process
10 | */
11 | void processRecord(SingleRecord record);
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorActivity.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface RecordProcessorActivity {
7 |
8 | /** Processes all records in the dataset */
9 | int processRecords();
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/RecordProcessorImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | /** Fake record processor implementation. */
7 | public final class RecordProcessorImpl implements RecordProcessor {
8 |
9 | private static final Logger log = LoggerFactory.getLogger(RecordProcessorImpl.class);
10 |
11 | @Override
12 | public void processRecord(SingleRecord record) {
13 | // Fake processing logic
14 | try {
15 | Thread.sleep(100);
16 | log.info("Processed " + record);
17 | } catch (InterruptedException ignored) {
18 | return;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/heartbeatingactivity/SingleRecord.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.heartbeatingactivity;
2 |
3 | /** Record to process. A real application would add a use case specific data. */
4 | public class SingleRecord {
5 | private int id;
6 |
7 | public SingleRecord(int id) {
8 | this.id = id;
9 | }
10 |
11 | /** JSON deserializer needs it */
12 | public SingleRecord() {}
13 |
14 | public int getId() {
15 | return id;
16 | }
17 |
18 | @Override
19 | public String toString() {
20 | return "Record{" + "id=" + id + '}';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchStarter.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.iterator;
2 |
3 | import static io.temporal.samples.batch.iterator.IteratorBatchWorker.TASK_QUEUE;
4 |
5 | import io.temporal.api.common.v1.WorkflowExecution;
6 | import io.temporal.client.WorkflowClient;
7 | import io.temporal.client.WorkflowOptions;
8 | import io.temporal.serviceclient.WorkflowServiceStubs;
9 |
10 | /** Starts a single execution of IteratorBatchWorkflow. */
11 | public class IteratorBatchStarter {
12 |
13 | public static void main(String[] args) {
14 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
15 | WorkflowClient workflowClient = WorkflowClient.newInstance(service);
16 | WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build();
17 | IteratorBatchWorkflow batchWorkflow =
18 | workflowClient.newWorkflowStub(IteratorBatchWorkflow.class, options);
19 | WorkflowExecution execution = WorkflowClient.start(batchWorkflow::processBatch, 5, 0);
20 | System.out.println(
21 | "Started batch workflow. WorkflowId="
22 | + execution.getWorkflowId()
23 | + ", RunId="
24 | + execution.getRunId());
25 | System.exit(0);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.iterator;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 |
8 | /**
9 | * A worker process that hosts implementations of IteratorBatchWorkflow and RecordProcessorWorkflow
10 | * as well as RecordLoader activity.
11 | */
12 | public final class IteratorBatchWorker {
13 |
14 | static final String TASK_QUEUE = "IteratorBatch";
15 |
16 | public static void main(String[] args) {
17 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
18 | WorkflowClient client = WorkflowClient.newInstance(service);
19 |
20 | WorkerFactory factory = WorkerFactory.newInstance(client);
21 | Worker worker = factory.newWorker(TASK_QUEUE);
22 |
23 | worker.registerWorkflowImplementationTypes(
24 | IteratorBatchWorkflowImpl.class, RecordProcessorWorkflowImpl.class);
25 |
26 | worker.registerActivitiesImplementations(new RecordLoaderImpl());
27 | factory.start();
28 | System.out.println("Worker started for task queue: " + TASK_QUEUE);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/IteratorBatchWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.iterator;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface IteratorBatchWorkflow {
8 |
9 | /**
10 | * Processes the batch of records.
11 | *
12 | * @param offset the offset of the first record to process. 0 to start the batch processing.
13 | * @param pageSize the number of records to process in a single workflow run.
14 | * @return total number of processed records.
15 | */
16 | @WorkflowMethod
17 | int processBatch(int pageSize, int offset);
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/README.md:
--------------------------------------------------------------------------------
1 | A sample implementation of the Workflow iterator pattern.
2 |
3 | A workflow starts a configured number of Child Workflows in parallel. Each child processes a single record.
4 | After all children complete, the parent calls continue-as-new and starts the children for the next page of records.
5 |
6 | This allows processing a set of records of any size. The advantage of this approach is simplicity.
7 | The main disadvantage is that it processes records in batches, with each batch waiting for the slowest child workflow.
8 |
9 | A variation of this pattern runs activities instead of child workflows.
10 |
11 | #### Running the Iterator Batch Sample
12 |
13 | The sample has two executables. Execute each command in a separate terminal window.
14 |
15 | The first command runs the Worker that hosts the Workflow and Activity Executions.
16 |
17 | ```bash
18 | ./gradlew -q execute -PmainClass=io.temporal.samples.batch.iterator.IteratorBatchWorker
19 | ```
20 |
21 | The second command start the Workflow Execution. Each time the command runs, it starts a new Workflow Execution.
22 |
23 | ```bash
24 | ./gradlew -q execute -PmainClass=io.temporal.samples.batch.iterator.IteratorBatchStarter
25 | ```
26 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoader.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.iterator;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 | import java.util.List;
5 |
6 | /**
7 | * Activity that is used to iterate over a list of records.
8 | *
9 | *
A specific implementation depends on a use case. For example, it can execute an SQL DB query
10 | * or read a comma delimited file. More complex use cases would need passing a different type of
11 | * offset parameter.
12 | */
13 | @ActivityInterface
14 | public interface RecordLoader {
15 |
16 | /**
17 | * Returns the next page of records.
18 | *
19 | * @param offset offset of the next page.
20 | * @param pageSize maximum number of records to return.
21 | * @return empty list if no more records to process.
22 | */
23 | List getRecords(int pageSize, int offset);
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/RecordLoaderImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.iterator;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /** Fake implementation of RecordLoader. */
7 | public final class RecordLoaderImpl implements RecordLoader {
8 |
9 | // The sample always returns 5 pages.
10 | // The real application would iterate over an existing dataset or file.
11 | public static final int PAGE_COUNT = 5;
12 |
13 | @Override
14 | public List getRecords(int pageSize, int offset) {
15 | List records = new ArrayList<>(pageSize);
16 | if (offset < pageSize * PAGE_COUNT) {
17 | for (int i = 0; i < pageSize; i++) {
18 | records.add(new SingleRecord(offset + i));
19 | }
20 | }
21 | return records;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.iterator;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | /** Workflow that implements processing of a single record. */
7 | @WorkflowInterface
8 | public interface RecordProcessorWorkflow {
9 |
10 | /** Processes a single record */
11 | @WorkflowMethod
12 | void processRecord(SingleRecord r);
13 | }
14 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/RecordProcessorWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.iterator;
2 |
3 | import io.temporal.workflow.Workflow;
4 | import java.time.Duration;
5 | import java.util.Random;
6 | import org.slf4j.Logger;
7 |
8 | /** Fake RecordProcessorWorkflow implementation. */
9 | public class RecordProcessorWorkflowImpl implements RecordProcessorWorkflow {
10 | public static final Logger log = Workflow.getLogger(RecordProcessorWorkflowImpl.class);
11 | private final Random random = Workflow.newRandom();
12 |
13 | @Override
14 | public void processRecord(SingleRecord r) {
15 | // Simulate some processing
16 | Workflow.sleep(Duration.ofSeconds(random.nextInt(30)));
17 | log.info("Processed " + r);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/iterator/SingleRecord.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.iterator;
2 |
3 | /** Record to process. A real application would add a use case specific data. */
4 | public class SingleRecord {
5 | private int id;
6 |
7 | public SingleRecord(int id) {
8 | this.id = id;
9 | }
10 |
11 | /** JSON deserializer needs it */
12 | public SingleRecord() {}
13 |
14 | public int getId() {
15 | return id;
16 | }
17 |
18 | @Override
19 | public String toString() {
20 | return "SingleRecord{" + "id=" + id + '}';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchProgress.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | import java.util.Set;
4 |
5 | /** Used as a result of {@link SlidingWindowBatchWorkflow#getProgress()} query. */
6 | public final class BatchProgress {
7 |
8 | private final int progress;
9 |
10 | private final Set currentRecords;
11 |
12 | public BatchProgress(int progress, Set currentRecords) {
13 | this.progress = progress;
14 | this.currentRecords = currentRecords;
15 | }
16 |
17 | /** Count of completed record processing child workflows. */
18 | public int getProgress() {
19 | return progress;
20 | }
21 |
22 | /** Ids of records that are currently being processed by child workflows. */
23 | public Set getCurrentRecords() {
24 | return currentRecords;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/BatchWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface BatchWorkflow {
8 |
9 | /**
10 | * Processes a batch of records using multiple parallel sliding window workflows.
11 | *
12 | * @param pageSize the number of records to start processing in a single sliding window workflow
13 | * run.
14 | * @param slidingWindowSize the number of records to process in parallel by a single sliding
15 | * window workflow. Can be larger than the pageSize.
16 | * @param partitions defines the number of SlidingWindowBatchWorkflows to run in parallel. If
17 | * number of partitions is too low the update rate of a single SlidingWindowBatchWorkflows can
18 | * get too high.
19 | * @return total number of processed records.
20 | */
21 | @WorkflowMethod
22 | int processBatch(int pageSize, int slidingWindowSize, int partitions);
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoader.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 | import java.util.List;
5 |
6 | @ActivityInterface
7 | public interface RecordLoader {
8 |
9 | /**
10 | * Returns the next page of records.
11 | *
12 | * @param offset offset of the next page.
13 | * @param pageSize maximum number of records to return.
14 | * @return empty list if no more records to process.
15 | */
16 | List getRecords(int pageSize, int offset);
17 |
18 | /**
19 | * Returns the total record count.
20 | *
21 | *
Used to divide record ranges among partitions. Some applications might choose a completely
22 | * different approach for partitioning the data set.
23 | */
24 | int getRecordCount();
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordLoaderImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /** Fake loader implementation. The real application would iterate over a dataset or file. */
7 | public final class RecordLoaderImpl implements RecordLoader {
8 |
9 | private static final int TOTAL_COUNT = 300;
10 |
11 | @Override
12 | public List getRecords(int pageSize, int offset) {
13 | List records = new ArrayList<>(pageSize);
14 | if (offset < TOTAL_COUNT) {
15 | for (int i = offset; i < Math.min(offset + pageSize, TOTAL_COUNT); i++) {
16 | records.add(new SingleRecord(i));
17 | }
18 | }
19 | return records;
20 | }
21 |
22 | @Override
23 | public int getRecordCount() {
24 | return TOTAL_COUNT;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/RecordProcessorWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | /** Workflow that implements processing of a single record. */
7 | @WorkflowInterface
8 | public interface RecordProcessorWorkflow {
9 |
10 | /**
11 | * Processes a single record. Must report completion to a parent through {@link
12 | * SlidingWindowBatchWorkflow#reportCompletion(int)}
13 | */
14 | @WorkflowMethod
15 | void processRecord(SingleRecord r);
16 | }
17 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/SingleRecord.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | /** Record to process. */
4 | public class SingleRecord {
5 | private int id;
6 |
7 | public SingleRecord(int id) {
8 | this.id = id;
9 | }
10 |
11 | /** Needed for JSON deserialization. */
12 | public SingleRecord() {}
13 |
14 | public int getId() {
15 | return id;
16 | }
17 |
18 | @Override
19 | public String toString() {
20 | return "SingleRecord{" + "id=" + id + '}';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchStarter.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | import static io.temporal.samples.batch.slidingwindow.SlidingWindowBatchWorker.TASK_QUEUE;
4 |
5 | import io.temporal.client.WorkflowClient;
6 | import io.temporal.client.WorkflowOptions;
7 | import io.temporal.serviceclient.WorkflowServiceStubs;
8 |
9 | public class SlidingWindowBatchStarter {
10 |
11 | @SuppressWarnings("CatchAndPrintStackTrace")
12 | public static void main(String[] args) {
13 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
14 | WorkflowClient workflowClient = WorkflowClient.newInstance(service);
15 | WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build();
16 | BatchWorkflow batchWorkflow = workflowClient.newWorkflowStub(BatchWorkflow.class, options);
17 | WorkflowClient.start(batchWorkflow::processBatch, 10, 25, 3);
18 | System.out.println("Started batch workflow with 3 partitions");
19 | System.exit(0);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 |
8 | /** Hosts sliding window batch sample workflow and activity implementations. */
9 | public final class SlidingWindowBatchWorker {
10 |
11 | static final String TASK_QUEUE = "SlidingWindow";
12 |
13 | public static void main(String[] args) {
14 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
15 | WorkflowClient client = WorkflowClient.newInstance(service);
16 |
17 | WorkerFactory factory = WorkerFactory.newInstance(client);
18 | Worker worker = factory.newWorker(TASK_QUEUE);
19 |
20 | worker.registerWorkflowImplementationTypes(
21 | BatchWorkflowImpl.class,
22 | SlidingWindowBatchWorkflowImpl.class,
23 | RecordProcessorWorkflowImpl.class);
24 | worker.registerActivitiesImplementations(new RecordLoaderImpl());
25 |
26 | factory.start();
27 |
28 | System.out.println("Worker started for task queue: " + TASK_QUEUE);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/batch/slidingwindow/SlidingWindowBatchWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.batch.slidingwindow;
2 |
3 | import io.temporal.workflow.QueryMethod;
4 | import io.temporal.workflow.SignalMethod;
5 | import io.temporal.workflow.WorkflowInterface;
6 | import io.temporal.workflow.WorkflowMethod;
7 |
8 | @WorkflowInterface
9 | public interface SlidingWindowBatchWorkflow {
10 |
11 | /**
12 | * Process the batch of records.
13 | *
14 | * @return total number of processed records.
15 | */
16 | @WorkflowMethod
17 | int processBatch(ProcessBatchInput input);
18 |
19 | @SignalMethod
20 | void reportCompletion(int recordId);
21 |
22 | @QueryMethod
23 | BatchProgress getProgress();
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/bookingsaga/Booking.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.bookingsaga;
2 |
3 | public final class Booking {
4 | private String carReservationID;
5 | private String hotelReservationID;
6 | private String flightReservationID;
7 |
8 | /** Empty constructor to keep Jackson serializer happy. */
9 | public Booking() {}
10 |
11 | public Booking(String carReservationID, String hotelReservationID, String flightReservationID) {
12 | this.carReservationID = carReservationID;
13 | this.hotelReservationID = hotelReservationID;
14 | this.flightReservationID = flightReservationID;
15 | }
16 |
17 | public String getCarReservationID() {
18 | return carReservationID;
19 | }
20 |
21 | public String getHotelReservationID() {
22 | return hotelReservationID;
23 | }
24 |
25 | public String getFlightReservationID() {
26 | return flightReservationID;
27 | }
28 |
29 | @Override
30 | public String toString() {
31 | return "Booking{"
32 | + "carReservationID='"
33 | + carReservationID
34 | + '\''
35 | + ", hotelReservationID='"
36 | + hotelReservationID
37 | + '\''
38 | + ", flightReservationID='"
39 | + flightReservationID
40 | + '\''
41 | + '}';
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/bookingsaga/README.md:
--------------------------------------------------------------------------------
1 | ## Saga example: trip booking
2 |
3 | Temporal implementation of
4 | the [Camunda BPMN trip booking example](https://github.com/berndruecker/trip-booking-saga-java) which demonstrates
5 | Temporal approach to SAGA.
6 |
7 | Run the following command to start the sample:
8 |
9 | ```bash
10 | ./gradlew -q execute -PmainClass=io.temporal.samples.bookingsaga.TripBookingSaga
11 | ```
12 |
13 | Note that the booking is expected to fail to demonstrate the compensation flow.
14 |
15 | Sample unit
16 | testing: [TripBookingWorkflowTest](https://github.com/temporalio/samples-java/blob/main/core/src/test/java/io/temporal/samples/bookingsaga/TripBookingWorkflowTest.java)
17 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingClient.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.bookingsaga;
2 |
3 | import com.google.common.base.Throwables;
4 | import io.temporal.client.WorkflowClient;
5 | import io.temporal.client.WorkflowOptions;
6 | import io.temporal.serviceclient.WorkflowServiceStubs;
7 |
8 | public class TripBookingClient {
9 |
10 | static final String TASK_QUEUE = "TripBooking";
11 |
12 | public static void main(String[] args) {
13 | // gRPC stubs wrapper that talks to the local docker instance of temporal service.
14 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
15 | // client that can be used to start and signal workflows
16 | WorkflowClient client = WorkflowClient.newInstance(service);
17 |
18 | WorkflowOptions options =
19 | WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId("Booking1").build();
20 | TripBookingWorkflow trip = client.newWorkflowStub(TripBookingWorkflow.class, options);
21 | try {
22 | Booking booking = trip.bookTrip("trip1");
23 | System.out.println("Booking: " + booking);
24 | } catch (Exception e) {
25 | System.out.println(Throwables.getStackTraceAsString(e));
26 | }
27 | System.exit(0);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/bookingsaga/TripBookingWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.bookingsaga;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface TripBookingWorkflow {
8 | @WorkflowMethod
9 | Booking bookTrip(String name);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/bookingsyncsaga/Booking.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.bookingsyncsaga;
2 |
3 | public final class Booking {
4 | private final String carReservationID;
5 | private final String hotelReservationID;
6 | private final String flightReservationID;
7 |
8 | public Booking(String carReservationID, String hotelReservationID, String flightReservationID) {
9 | this.carReservationID = carReservationID;
10 | this.hotelReservationID = hotelReservationID;
11 | this.flightReservationID = flightReservationID;
12 | }
13 |
14 | public String getCarReservationID() {
15 | return carReservationID;
16 | }
17 |
18 | public String getHotelReservationID() {
19 | return hotelReservationID;
20 | }
21 |
22 | public String getFlightReservationID() {
23 | return flightReservationID;
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | return "Booking{"
29 | + "carReservationID='"
30 | + carReservationID
31 | + '\''
32 | + ", hotelReservationID='"
33 | + hotelReservationID
34 | + '\''
35 | + ", flightReservationID='"
36 | + flightReservationID
37 | + '\''
38 | + '}';
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/bookingsyncsaga/README.md:
--------------------------------------------------------------------------------
1 | ## Saga example: synchronous trip booking
2 |
3 | The sample demonstrates low latency workflow with client synchronously waiting for result using an update.
4 | In case of failures the caller is unblocked and workflow continues executing compensations
5 | for as long as needed.
6 |
7 | Run the following command to start the worker:
8 |
9 | ```bash
10 | ./gradlew -q execute -PmainClass=io.temporal.samples.bookingsyncsaga.TripBookingWorker
11 | ```
12 |
13 | Run the following command to request a booking.
14 | Note that the booking is expected to fail to demonstrate the compensation flow.
15 |
16 | ```bash
17 | ./gradlew -q execute -PmainClass=io.temporal.samples.bookingsyncsaga.TripBookingClient
18 | ```
19 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/bookingsyncsaga/TripBookingWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.bookingsyncsaga;
2 |
3 | import io.temporal.workflow.UpdateMethod;
4 | import io.temporal.workflow.WorkflowInterface;
5 | import io.temporal.workflow.WorkflowMethod;
6 |
7 | @WorkflowInterface
8 | public interface TripBookingWorkflow {
9 | @WorkflowMethod
10 | void bookTrip(String name);
11 |
12 | /**
13 | * Used to wait for booking completion or failure. After this method returns a failure workflow
14 | * keeps running executing compensations.
15 | *
16 | * @return booking information.
17 | */
18 | @UpdateMethod
19 | Booking waitForBooking();
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/README.md:
--------------------------------------------------------------------------------
1 | # Demo Workflow Interceptor
2 |
3 | The sample demonstrates:
4 | - the use of a simple Worker Workflow Interceptor that counts the number of Workflow Executions, Child Workflow Executions, and Activity Executions as well as the number of Signals and Queries.
5 | - the use of a simple Client Workflow Interceptor that counts the number of Workflow Executions as well as the number of Signals, Queries and GetResult invocations.
6 |
7 | Run the following command to start the sample:
8 |
9 | ```bash
10 | ./gradlew -q execute -PmainClass=io.temporal.samples.countinterceptor.InterceptorStarter
11 | ```
12 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/SimpleClientInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor;
2 |
3 | import io.temporal.common.interceptors.WorkflowClientCallsInterceptor;
4 | import io.temporal.common.interceptors.WorkflowClientInterceptorBase;
5 |
6 | public class SimpleClientInterceptor extends WorkflowClientInterceptorBase {
7 |
8 | private ClientCounter clientCounter;
9 |
10 | public SimpleClientInterceptor(ClientCounter clientCounter) {
11 | this.clientCounter = clientCounter;
12 | }
13 |
14 | @Override
15 | public WorkflowClientCallsInterceptor workflowClientCallsInterceptor(
16 | WorkflowClientCallsInterceptor next) {
17 | return new SimpleClientCallsInterceptor(next, clientCounter);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountActivityInboundCallsInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor;
2 |
3 | import io.temporal.activity.ActivityExecutionContext;
4 | import io.temporal.common.interceptors.ActivityInboundCallsInterceptor;
5 | import io.temporal.common.interceptors.ActivityInboundCallsInterceptorBase;
6 |
7 | public class SimpleCountActivityInboundCallsInterceptor
8 | extends ActivityInboundCallsInterceptorBase {
9 |
10 | private ActivityExecutionContext activityExecutionContext;
11 |
12 | public SimpleCountActivityInboundCallsInterceptor(ActivityInboundCallsInterceptor next) {
13 | super(next);
14 | }
15 |
16 | @Override
17 | public void init(ActivityExecutionContext context) {
18 | this.activityExecutionContext = context;
19 | super.init(context);
20 | }
21 |
22 | @Override
23 | public ActivityOutput execute(ActivityInput input) {
24 | WorkerCounter.add(
25 | this.activityExecutionContext.getInfo().getWorkflowId(),
26 | WorkerCounter.NUM_OF_ACTIVITY_EXECUTIONS);
27 | return super.execute(input);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkerInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor;
2 |
3 | import io.temporal.common.interceptors.*;
4 |
5 | public class SimpleCountWorkerInterceptor extends WorkerInterceptorBase {
6 |
7 | @Override
8 | public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) {
9 | return new SimpleCountWorkflowInboundCallsInterceptor(next);
10 | }
11 |
12 | @Override
13 | public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) {
14 | return new SimpleCountActivityInboundCallsInterceptor(next);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/SimpleCountWorkflowOutboundCallsInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor;
2 |
3 | import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor;
4 | import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptorBase;
5 | import io.temporal.workflow.Workflow;
6 |
7 | public class SimpleCountWorkflowOutboundCallsInterceptor
8 | extends WorkflowOutboundCallsInterceptorBase {
9 |
10 | public SimpleCountWorkflowOutboundCallsInterceptor(WorkflowOutboundCallsInterceptor next) {
11 | super(next);
12 | }
13 |
14 | @Override
15 | public ChildWorkflowOutput executeChildWorkflow(ChildWorkflowInput input) {
16 | WorkerCounter.add(
17 | Workflow.getInfo().getWorkflowId(), WorkerCounter.NUM_OF_CHILD_WORKFLOW_EXECUTIONS);
18 | return super.executeChildWorkflow(input);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor.activities;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface MyActivities {
7 | String sayHello(String name, String title);
8 |
9 | String sayGoodBye(String name, String title);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/activities/MyActivitiesImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor.activities;
2 |
3 | public class MyActivitiesImpl implements MyActivities {
4 | @Override
5 | public String sayHello(String name, String title) {
6 | return "Hello " + title + " " + name;
7 | }
8 |
9 | @Override
10 | public String sayGoodBye(String name, String title) {
11 | return "Goodbye " + title + " " + name;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor.workflow;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface MyChildWorkflow {
8 | @WorkflowMethod
9 | String execChild(String name, String title);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyChildWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor.workflow;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.samples.countinterceptor.activities.MyActivities;
5 | import io.temporal.workflow.Workflow;
6 | import java.time.Duration;
7 |
8 | public class MyChildWorkflowImpl implements MyChildWorkflow {
9 | @Override
10 | public String execChild(String name, String title) {
11 | MyActivities activities =
12 | Workflow.newActivityStub(
13 | MyActivities.class,
14 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build());
15 |
16 | String result = activities.sayHello(name, title);
17 | result += activities.sayGoodBye(name, title);
18 |
19 | return result;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/countinterceptor/workflow/MyWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.countinterceptor.workflow;
2 |
3 | import io.temporal.workflow.QueryMethod;
4 | import io.temporal.workflow.SignalMethod;
5 | import io.temporal.workflow.WorkflowInterface;
6 | import io.temporal.workflow.WorkflowMethod;
7 |
8 | @WorkflowInterface
9 | public interface MyWorkflow {
10 | @WorkflowMethod
11 | String exec();
12 |
13 | @SignalMethod
14 | void signalNameAndTitle(String greeting, String title);
15 |
16 | @SignalMethod
17 | void exit();
18 |
19 | @QueryMethod
20 | String queryName();
21 |
22 | @QueryMethod
23 | String queryTitle();
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.customchangeversion;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface CustomChangeVersionActivities {
7 | String customOne(String input);
8 |
9 | String customTwo(String input);
10 |
11 | String customThree(String input);
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionActivitiesImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.customchangeversion;
2 |
3 | public class CustomChangeVersionActivitiesImpl implements CustomChangeVersionActivities {
4 | @Override
5 | public String customOne(String input) {
6 | return "\ncustomOne activity - " + input;
7 | }
8 |
9 | @Override
10 | public String customTwo(String input) {
11 | return "\ncustomTwo activity - " + input;
12 | }
13 |
14 | @Override
15 | public String customThree(String input) {
16 | return "\ncustomThree activity - " + input;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/customchangeversion/CustomChangeVersionWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.customchangeversion;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface CustomChangeVersionWorkflow {
8 | @WorkflowMethod
9 | String run(String input);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/customchangeversion/README.md:
--------------------------------------------------------------------------------
1 | ## Custom Change Version Search Attribute Sample
2 |
3 | This sample shows how to upsert custom search attribute when adding a version change to your workflow code.
4 | It is a current workaround until feature https://github.com/temporalio/sdk-java/issues/587 is implemented.
5 | Purpose of upserting a custom search attribute when addint new versions is to then be able to use
6 | visibility api to search for running/completed executions which are on a specific version. It is also useful to see
7 | if there are no running executions on specific change version in order to remove certain no longer used versioned change
8 | if/else block from your workflow code, so it no longer has to be maintained.
9 |
10 | To run this sample:
11 | ```bash
12 | ./gradlew -q execute -PmainClass=io.temporal.samples.customchangeversion.CustomChangeVersionStarter
13 | ```
14 |
15 | After running this sample you can go to your Web UI or use Temporal CLI to search for specific CustomChangeVersion, for example:
16 |
17 | ```
18 | temporal workflow list -q "CustomChangeVersion='add-v3-activity-change-1'"
19 | ```
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/dsl/DslActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.dsl;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface DslActivities {
7 | String one();
8 |
9 | String two();
10 |
11 | String three();
12 |
13 | String four();
14 | }
15 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/dsl/DslActivitiesImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.dsl;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | public class DslActivitiesImpl implements DslActivities {
6 | @Override
7 | public String one() {
8 | sleep(1);
9 | return "Activity one done...";
10 | }
11 |
12 | @Override
13 | public String two() {
14 | sleep(1);
15 | return "Activity two done...";
16 | }
17 |
18 | @Override
19 | public String three() {
20 | sleep(1);
21 | return "Activity three done...";
22 | }
23 |
24 | @Override
25 | public String four() {
26 | sleep(1);
27 | return "Activity four done...";
28 | }
29 |
30 | private void sleep(int seconds) {
31 | try {
32 | Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
33 | } catch (InterruptedException ee) {
34 | // Empty
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/dsl/DslWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.dsl;
2 |
3 | import io.temporal.samples.dsl.model.Flow;
4 | import io.temporal.workflow.WorkflowInterface;
5 | import io.temporal.workflow.WorkflowMethod;
6 |
7 | @WorkflowInterface
8 | public interface DslWorkflow {
9 | @WorkflowMethod
10 | String run(Flow flow, String input);
11 | }
12 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/dsl/README.md:
--------------------------------------------------------------------------------
1 | # DSL Sample
2 |
3 | This sample shows how to use a DSL on top of Temporal.
4 | The sample defines a number of domain specific json samples
5 | which are used to define steps of actions to be performed by our workflow.
6 |
7 | As with all samples, use the following at your own risk.
8 |
9 | As a rule, DSLs provide limited and restrictive functionality.
10 | They are not suitable for full expressive development.
11 |
12 | In many cases, it's better to build customized DSLs to optimize simplicity and domain targeting for your particular use case.
13 |
14 | ## Run the sample
15 |
16 | 1Start the Starter
17 |
18 | ```bash
19 | ./gradlew -q execute -PmainClass=io.temporal.samples.dsl.Starter
20 | ```
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/dsl/model/Flow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.dsl.model;
2 |
3 | import java.util.List;
4 |
5 | public class Flow {
6 | private String id;
7 | private String name;
8 | private String description;
9 | private List actions;
10 |
11 | public Flow() {}
12 |
13 | public Flow(String id, String name, String description, List actions) {
14 | this.id = id;
15 | this.name = name;
16 | this.description = description;
17 | this.actions = actions;
18 | }
19 |
20 | public String getId() {
21 | return id;
22 | }
23 |
24 | public void setId(String id) {
25 | this.id = id;
26 | }
27 |
28 | public String getName() {
29 | return name;
30 | }
31 |
32 | public void setName(String name) {
33 | this.name = name;
34 | }
35 |
36 | public String getDescription() {
37 | return description;
38 | }
39 |
40 | public void setDescription(String description) {
41 | this.description = description;
42 | }
43 |
44 | public List getActions() {
45 | return actions;
46 | }
47 |
48 | public void setActions(List actions) {
49 | this.actions = actions;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/earlyreturn/EarlyReturnWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.earlyreturn;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.worker.Worker;
5 | import io.temporal.worker.WorkerFactory;
6 |
7 | public class EarlyReturnWorker {
8 | private static final String TASK_QUEUE = "EarlyReturnTaskQueue";
9 |
10 | public static void main(String[] args) {
11 | WorkflowClient client = EarlyReturnClient.setupWorkflowClient();
12 | startWorker(client);
13 | }
14 |
15 | private static void startWorker(WorkflowClient client) {
16 | WorkerFactory factory = WorkerFactory.newInstance(client);
17 | Worker worker = factory.newWorker(TASK_QUEUE);
18 |
19 | worker.registerWorkflowImplementationTypes(TransactionWorkflowImpl.class);
20 | worker.registerActivitiesImplementations(new TransactionActivitiesImpl());
21 |
22 | factory.start();
23 | System.out.println("Worker started");
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/earlyreturn/README.md:
--------------------------------------------------------------------------------
1 | ### Early-Return Sample
2 |
3 | This sample demonstrates an early-return from a workflow.
4 |
5 | By utilizing Update-with-Start, a client can start a new workflow and synchronously receive
6 | a response mid-workflow, while the workflow continues to run to completion.
7 |
8 | To run the sample, start the worker:
9 | ```bash
10 | ./gradlew -q execute -PmainClass=io.temporal.samples.earlyreturn.EarlyReturnWorker
11 | ```
12 |
13 | Then, start the client:
14 |
15 | ```bash
16 | ./gradlew -q execute -PmainClass=io.temporal.samples.earlyreturn.EarlyReturnClient
17 | ```
18 |
19 | * The client will start a workflow using Update-With-Start.
20 | * Update-With-Start will trigger an initialization step.
21 | * If the initialization step succeeds (default), intialization will return to the client with a transaction ID and the workflow will continue. The workflow will then complete and return the final result.
22 | * If the intitialization step fails (amount <= 0), the workflow will return to the client with an error message and the workflow will run an activity to cancel the transaction.
23 |
24 | To trigger a failed initialization, set the amount to <= 0 in the `EarlyReturnClient` class's `runWorkflowWithUpdateWithStart` method and re-run the client.
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/earlyreturn/TransactionActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.earlyreturn;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 | import io.temporal.activity.ActivityMethod;
5 |
6 | @ActivityInterface
7 | public interface TransactionActivities {
8 | @ActivityMethod
9 | Transaction mintTransactionId(TransactionRequest txRequest);
10 |
11 | @ActivityMethod
12 | Transaction initTransaction(Transaction tx);
13 |
14 | @ActivityMethod
15 | void cancelTransaction(Transaction tx);
16 |
17 | @ActivityMethod
18 | void completeTransaction(Transaction tx);
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/earlyreturn/TransactionRequest.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.earlyreturn;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | public final class TransactionRequest {
7 | private final String sourceAccount;
8 | private final String targetAccount;
9 | private final int amount;
10 |
11 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
12 | public TransactionRequest(
13 | @JsonProperty("sourceAccount") String sourceAccount,
14 | @JsonProperty("targetAccount") String targetAccount,
15 | @JsonProperty("amount") int amount) {
16 | this.sourceAccount = sourceAccount;
17 | this.targetAccount = targetAccount;
18 | this.amount = amount;
19 | }
20 |
21 | @JsonProperty("sourceAccount")
22 | public String getSourceAccount() {
23 | return sourceAccount;
24 | }
25 |
26 | @JsonProperty("targetAccount")
27 | public String getTargetAccount() {
28 | return targetAccount;
29 | }
30 |
31 | @JsonProperty("amount")
32 | public int getAmount() {
33 | return amount;
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return String.format(
39 | "TransactionRequest{sourceAccount='%s', targetAccount='%s', amount=%d}",
40 | sourceAccount, targetAccount, amount);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/earlyreturn/TransactionWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.earlyreturn;
2 |
3 | import io.temporal.workflow.UpdateMethod;
4 | import io.temporal.workflow.WorkflowInterface;
5 | import io.temporal.workflow.WorkflowMethod;
6 |
7 | @WorkflowInterface
8 | public interface TransactionWorkflow {
9 | @WorkflowMethod
10 | TxResult processTransaction(TransactionRequest txRequest);
11 |
12 | @UpdateMethod(name = "early-return")
13 | TxResult returnInitResult();
14 | }
15 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/earlyreturn/TxResult.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.earlyreturn;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | public class TxResult {
7 | private final String transactionId;
8 | private final String status;
9 |
10 | // Jackson-compatible constructor with @JsonCreator and @JsonProperty annotations
11 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
12 | public TxResult(
13 | @JsonProperty("transactionId") String transactionId, @JsonProperty("status") String status) {
14 | this.transactionId = transactionId;
15 | this.status = status;
16 | }
17 |
18 | @JsonProperty("transactionId")
19 | public String getTransactionId() {
20 | return transactionId;
21 | }
22 |
23 | @JsonProperty("status")
24 | public String getStatus() {
25 | return status;
26 | }
27 |
28 | @Override
29 | public String toString() {
30 | return String.format("InitResult{transactionId='%s', status='%s'}", transactionId, status);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheck.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.encodefailures;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface CustomerAgeCheck {
8 | @WorkflowMethod
9 | public String validateCustomer(MyCustomer customer);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/encodefailures/CustomerAgeCheckImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.encodefailures;
2 |
3 | import io.temporal.workflow.Workflow;
4 |
5 | public class CustomerAgeCheckImpl implements CustomerAgeCheck {
6 | @Override
7 | public String validateCustomer(MyCustomer customer) {
8 | // Note we have explicitly set InvalidCustomerException type to fail workflow execution
9 | // We wrap it using Workflow.wrap so can throw as unchecked
10 | if (customer.getAge() < 21) {
11 | throw Workflow.wrap(
12 | new InvalidCustomerException("customer " + customer.getName() + " is under age."));
13 | } else {
14 | return "done...";
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/encodefailures/InvalidCustomerException.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.encodefailures;
2 |
3 | public class InvalidCustomerException extends Exception {
4 | public InvalidCustomerException(String errorMessage) {
5 | super(errorMessage);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/encodefailures/MyCustomer.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.encodefailures;
2 |
3 | public class MyCustomer {
4 | private String name;
5 | private int age;
6 | private boolean approved;
7 |
8 | public MyCustomer() {}
9 |
10 | public MyCustomer(String name, int age) {
11 | this.name = name;
12 | this.age = age;
13 | }
14 |
15 | public String getName() {
16 | return name;
17 | }
18 |
19 | public void setName(String name) {
20 | this.name = name;
21 | }
22 |
23 | public int getAge() {
24 | return age;
25 | }
26 |
27 | public void setAge(int age) {
28 | this.age = age;
29 | }
30 |
31 | public boolean isApproved() {
32 | return approved;
33 | }
34 |
35 | public void setApproved(boolean approved) {
36 | this.approved = approved;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/encodefailures/README.md:
--------------------------------------------------------------------------------
1 | # Using Codec to encode / decode failure messages
2 |
3 | The sample demonstrates how to set up a simple codec for encoding/decoding failure messages
4 | In this sample we set encodeFailureAttributes = true to our CodecDataConverter meaning we want to
5 | encode / decode failure messages as well.
6 | All it does is add a "Customer: " prefix to the message. You can expand on this to add any type of
7 | encoding that you might want to use.
8 |
9 | Our workflow does simple customer age check validation and fails if their age is < 21.
10 | In the Starter then we print out that the failure message client received on execution failure
11 | was indeed encoded using our codec.
12 |
13 | ## Running
14 |
15 | 1. Start Temporal Server with "default" namespace enabled.
16 | For example using local Docker:
17 |
18 | ```bash
19 | git clone https://github.com/temporalio/docker-compose.git
20 | cd docker-compose
21 | docker-compose up
22 | ```
23 |
24 | 2. Run the following command to start the sample:
25 |
26 | ```bash
27 | ./gradlew -q execute -PmainClass=io.temporal.samples.encodefailures.Starter
28 | ```
29 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/README.md:
--------------------------------------------------------------------------------
1 | # Excluding certain Workflow and Activity Types from interceptors
2 |
3 | This sample shows how to exclude certain workflow types and Activity types from Workflow and Activity Interceptors.
4 |
5 | 1. Start the Sample:
6 | ```bash
7 | ./gradlew -q execute -PmainClass=io.temporal.samples.excludefrominterceptor.RunMyWorkflows
8 | ```
9 |
10 | Observe the event histories of MyWorkflowOne and MyWorkflowTwo in your Temporal Web UI.
11 | You should see that even tho both executions were served by same worker so both had the interceptors applied,
12 | MyWorkflowTwo was excluded from being applied by these interceptors.
13 |
14 | Also from the Activity interceptor logs (System.out prints during sample run) note that
15 | only ActivityOne activity is being intercepted and not ActivityTwo or the "ForInterceptor" activities.
16 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.activities;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface ForInterceptorActivities {
7 | void forInterceptorActivityOne(Object output);
8 |
9 | void forInterceptorActivityTwo(Object output);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/ForInterceptorActivitiesImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.activities;
2 |
3 | public class ForInterceptorActivitiesImpl implements ForInterceptorActivities {
4 | @Override
5 | public void forInterceptorActivityOne(Object output) {}
6 |
7 | @Override
8 | public void forInterceptorActivityTwo(Object output) {}
9 | }
10 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.activities;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface MyActivities {
7 | void activityOne(String input);
8 |
9 | void activityTwo(String input);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/activities/MyActivitiesImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.activities;
2 |
3 | public class MyActivitiesImpl implements MyActivities {
4 | @Override
5 | public void activityOne(String input) {}
6 |
7 | @Override
8 | public void activityTwo(String input) {}
9 | }
10 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/interceptor/MyWorkerInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.interceptor;
2 |
3 | import io.temporal.common.interceptors.*;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | public class MyWorkerInterceptor extends WorkerInterceptorBase {
8 | private List excludeWorkflowTypes = new ArrayList<>();
9 | private List excludeActivityTypes = new ArrayList<>();
10 |
11 | public MyWorkerInterceptor() {}
12 |
13 | public MyWorkerInterceptor(List excludeWorkflowTypes) {
14 | this.excludeWorkflowTypes = excludeWorkflowTypes;
15 | }
16 |
17 | public MyWorkerInterceptor(List excludeWorkflowTypes, List excludeActivityTypes) {
18 | this.excludeWorkflowTypes = excludeWorkflowTypes;
19 | this.excludeActivityTypes = excludeActivityTypes;
20 | }
21 |
22 | @Override
23 | public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) {
24 | return new MyWorkflowInboundCallsInterceptor(excludeWorkflowTypes, next);
25 | }
26 |
27 | @Override
28 | public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) {
29 | return new MyActivityInboundCallsInterceptor(excludeActivityTypes, next);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.workflows;
2 |
3 | import io.temporal.workflow.WorkflowMethod;
4 |
5 | public interface MyWorkflow {
6 | @WorkflowMethod
7 | String execute(String input);
8 | }
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOne.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.workflows;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 |
5 | @WorkflowInterface
6 | public interface MyWorkflowOne extends MyWorkflow {}
7 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowOneImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.workflows;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.samples.excludefrominterceptor.activities.MyActivities;
5 | import io.temporal.workflow.Workflow;
6 | import java.time.Duration;
7 |
8 | public class MyWorkflowOneImpl implements MyWorkflowOne {
9 | private MyActivities activities =
10 | Workflow.newActivityStub(
11 | MyActivities.class,
12 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
13 |
14 | @Override
15 | public String execute(String input) {
16 | activities.activityOne(input);
17 | activities.activityTwo(input);
18 |
19 | return "done";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwo.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.workflows;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 |
5 | @WorkflowInterface
6 | public interface MyWorkflowTwo extends MyWorkflow {}
7 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/excludefrominterceptor/workflows/MyWorkflowTwoImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.excludefrominterceptor.workflows;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.samples.excludefrominterceptor.activities.MyActivities;
5 | import io.temporal.workflow.Workflow;
6 | import java.time.Duration;
7 |
8 | public class MyWorkflowTwoImpl implements MyWorkflowTwo {
9 | private MyActivities activities =
10 | Workflow.newActivityStub(
11 | MyActivities.class,
12 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
13 |
14 | @Override
15 | public String execute(String input) {
16 | activities.activityOne(input);
17 | activities.activityTwo(input);
18 |
19 | return "done";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/fileprocessing/FileProcessingWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.fileprocessing;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 | import java.net.URL;
6 |
7 | /** Contract for file processing workflow. */
8 | @WorkflowInterface
9 | public interface FileProcessingWorkflow {
10 | @WorkflowMethod
11 | void processFile(URL source, URL destination);
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/fileprocessing/README.md:
--------------------------------------------------------------------------------
1 | Demonstrates how to route tasks to specific Workers. This sample has a set of Activities that download a file, processes it, and uploads the result to a destination. Any Worker can execute the first Activity. However, the second and third Activities must be executed on the same host as the first one.
2 |
3 | #### Running the File Processing Sample
4 |
5 | The sample has two executables. Execute each command in a separate terminal window.
6 |
7 |
8 | The first command runs the Worker that hosts the Workflow and Activity Executions. To demonstrate that Activities execute together, we recommend running more than one instance of this Worker.
9 |
10 | ```bash
11 | ./gradlew -q execute -PmainClass=io.temporal.samples.fileprocessing.FileProcessingWorker
12 | ```
13 |
14 | The second command start the Workflow Execution. Each time the command runs, it starts a new Workflow Execution.
15 |
16 | ```bash
17 | ./gradlew -q execute -PmainClass=io.temporal.samples.fileprocessing.FileProcessingStarter
18 | ```
19 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/fileprocessing/StoreActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.fileprocessing;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 | import java.net.URL;
5 |
6 | @ActivityInterface
7 | public interface StoreActivities {
8 |
9 | final class TaskQueueFileNamePair {
10 | private String hostTaskQueue;
11 | private String fileName;
12 |
13 | public TaskQueueFileNamePair(String hostTaskQueue, String fileName) {
14 | this.hostTaskQueue = hostTaskQueue;
15 | this.fileName = fileName;
16 | }
17 |
18 | /** Jackson needs it */
19 | public TaskQueueFileNamePair() {}
20 |
21 | public String getHostTaskQueue() {
22 | return hostTaskQueue;
23 | }
24 |
25 | public String getFileName() {
26 | return fileName;
27 | }
28 | }
29 |
30 | /**
31 | * Upload file to remote location.
32 | *
33 | * @param localFileName file to upload
34 | * @param url remote location
35 | */
36 | void upload(String localFileName, URL url);
37 |
38 | /**
39 | * Process file.
40 | *
41 | * @param inputFileName source file name @@return processed file name
42 | */
43 | String process(String inputFileName);
44 |
45 | /**
46 | * Downloads file to local disk.
47 | *
48 | * @param url remote file location
49 | * @return local task queue and downloaded file name
50 | */
51 | TaskQueueFileNamePair download(URL url);
52 | }
53 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.getresultsasync;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface MyWorkflow {
8 | @WorkflowMethod
9 | String justSleep(int seconds);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/getresultsasync/MyWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.getresultsasync;
2 |
3 | import io.temporal.workflow.Workflow;
4 | import java.time.Duration;
5 |
6 | public class MyWorkflowImpl implements MyWorkflow {
7 | @Override
8 | public String justSleep(int seconds) {
9 | Workflow.sleep(Duration.ofSeconds(seconds));
10 | return "woke up after " + seconds + " seconds";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/getresultsasync/README.md:
--------------------------------------------------------------------------------
1 | # Get Workflow results async
2 |
3 | This sample shows the use of WorkflowStub.getResult and WorkflowStub.getResultAsync
4 | to show how the Temporal Client API can not only start Workflows async but also wait for their results
5 | async as well.
6 |
7 | ## Run the sample
8 |
9 | 1. Start the Worker:
10 |
11 | ```bash
12 | ./gradlew -q execute -PmainClass=io.temporal.samples.getresultsasync.Worker
13 | ```
14 |
15 | 2. Start the Starter
16 |
17 | ```bash
18 | ./gradlew -q execute -PmainClass=io.temporal.samples.getresultsasync.Starter
19 | ```
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/getresultsasync/Worker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.getresultsasync;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.WorkerFactory;
6 |
7 | public class Worker {
8 | public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
9 | public static final WorkflowClient client = WorkflowClient.newInstance(service);
10 | public static final WorkerFactory factory = WorkerFactory.newInstance(client);
11 | public static final String TASK_QUEUE_NAME = "asyncstartqueue";
12 |
13 | public static void main(String[] args) {
14 | io.temporal.worker.Worker worker = factory.newWorker(TASK_QUEUE_NAME);
15 | worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class);
16 |
17 | factory.start();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/listworkflows/Customer.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.listworkflows;
2 |
3 | public class Customer {
4 | private String accountNum;
5 | private String name;
6 | private String email;
7 | private String customerType;
8 |
9 | public Customer() {}
10 |
11 | public Customer(String accountNum, String name, String email, String customerType) {
12 | this.accountNum = accountNum;
13 | this.name = name;
14 | this.email = email;
15 | this.customerType = customerType;
16 | }
17 |
18 | public String getAccountNum() {
19 | return accountNum;
20 | }
21 |
22 | public void setAccountNum(String accountNum) {
23 | this.accountNum = accountNum;
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 |
34 | public String getEmail() {
35 | return email;
36 | }
37 |
38 | public void setEmail(String email) {
39 | this.email = email;
40 | }
41 |
42 | public String getCustomerType() {
43 | return customerType;
44 | }
45 |
46 | public void setCustomerType(String customerType) {
47 | this.customerType = customerType;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.listworkflows;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface CustomerActivities {
7 | void getCustomerAccount(Customer customer);
8 |
9 | void updateCustomerAccount(Customer customer, String message);
10 |
11 | void sendUpdateEmail(Customer customer);
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/listworkflows/CustomerActivitiesImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.listworkflows;
2 |
3 | import java.util.concurrent.TimeUnit;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | public class CustomerActivitiesImpl implements CustomerActivities {
8 |
9 | private static final Logger log = LoggerFactory.getLogger(CustomerActivitiesImpl.class);
10 |
11 | @Override
12 | public void getCustomerAccount(Customer customer) {
13 | // simulate some actual work...
14 | sleepSeconds(1);
15 | }
16 |
17 | @Override
18 | public void updateCustomerAccount(Customer customer, String message) {
19 | // simulate some actual work...
20 | sleepSeconds(1);
21 | }
22 |
23 | @Override
24 | public void sendUpdateEmail(Customer customer) {
25 | // simulate some actual work...
26 | sleepSeconds(1);
27 | }
28 |
29 | private void sleepSeconds(int seconds) {
30 | try {
31 | Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
32 | } catch (InterruptedException e) {
33 | // This is being swallowed on purpose
34 | Thread.currentThread().interrupt();
35 | log.error("Exception in thread sleep: ", e);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.listworkflows;
2 |
3 | import io.temporal.workflow.SignalMethod;
4 | import io.temporal.workflow.WorkflowInterface;
5 | import io.temporal.workflow.WorkflowMethod;
6 |
7 | @WorkflowInterface
8 | public interface CustomerWorkflow {
9 | @WorkflowMethod
10 | void updateAccountMessage(Customer customer, String message);
11 |
12 | @SignalMethod
13 | void exit();
14 | }
15 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/listworkflows/CustomerWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.listworkflows;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.common.RetryOptions;
5 | import io.temporal.workflow.Workflow;
6 | import java.time.Duration;
7 | import java.util.Optional;
8 |
9 | public class CustomerWorkflowImpl implements CustomerWorkflow {
10 | private boolean exit;
11 | private final CustomerActivities customerActivities =
12 | Workflow.newActivityStub(
13 | CustomerActivities.class,
14 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
15 | private final RetryOptions customerRetryOptions =
16 | RetryOptions.newBuilder().setMaximumAttempts(5).build();
17 | private final Duration expiration = Duration.ofMinutes(1);
18 |
19 | @Override
20 | public void updateAccountMessage(Customer customer, String message) {
21 |
22 | Workflow.retry(
23 | customerRetryOptions,
24 | Optional.of(expiration),
25 | () -> {
26 | customerActivities.getCustomerAccount(customer);
27 | customerActivities.updateCustomerAccount(customer, message);
28 | customerActivities.sendUpdateEmail(customer);
29 | });
30 |
31 | Workflow.await(Duration.ofMinutes(1), () -> exit);
32 | }
33 |
34 | @Override
35 | public void exit() {
36 | this.exit = true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/listworkflows/README.md:
--------------------------------------------------------------------------------
1 | # Demo List Workflows
2 |
3 | The sample demonstrates:
4 | 1) Setting custom search attributes for a Workflow
5 | 2) Using ListWorkflowExecutionsRequest and custom Search Attribute query to list
6 | Workflow Executions that match that query
7 |
8 | ## Running
9 |
10 | 1. Unlike the other examples, this one has to be started with Elasticsearch
11 | capabilities enabled. If you are using docker you can do that with:
12 |
13 | ```bash
14 | git clone https://github.com/temporalio/docker-compose.git
15 | cd docker-compose
16 | docker-compose -f docker-compose-cas-es.yml up
17 | ```
18 |
19 | 2.
20 | Run the following command to start the sample:
21 |
22 | ```bash
23 | ./gradlew -q execute -PmainClass=io.temporal.samples.listworkflows.Starter
24 | ```
25 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/metrics/MetricsUtils.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.metrics;
2 |
3 | import static java.nio.charset.StandardCharsets.UTF_8;
4 |
5 | import com.sun.net.httpserver.HttpServer;
6 | import io.micrometer.prometheus.PrometheusMeterRegistry;
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 | import java.net.InetSocketAddress;
10 |
11 | public class MetricsUtils {
12 |
13 | /**
14 | * Starts HttpServer to expose a scrape endpoint. See
15 | * https://micrometer.io/docs/registry/prometheus for more info.
16 | */
17 | public static HttpServer startPrometheusScrapeEndpoint(
18 | PrometheusMeterRegistry registry, int port) {
19 | try {
20 | HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
21 | server.createContext(
22 | "/metrics",
23 | httpExchange -> {
24 | String response = registry.scrape();
25 | httpExchange.sendResponseHeaders(200, response.getBytes(UTF_8).length);
26 | try (OutputStream os = httpExchange.getResponseBody()) {
27 | os.write(response.getBytes(UTF_8));
28 | }
29 | });
30 |
31 | server.start();
32 | return server;
33 | } catch (IOException e) {
34 | throw new RuntimeException(e);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/metrics/README.md:
--------------------------------------------------------------------------------
1 | # Setting up SDK metrics (Prometheus)
2 |
3 | This sample shows setup for SDK metrics.
4 |
5 | 1. Start the Worker:
6 | ```bash
7 | ./gradlew -q execute -PmainClass=io.temporal.samples.metrics.MetricsWorker
8 | ```
9 |
10 | 2. Start the Starter:
11 | ```bash
12 | ./gradlew -q execute -PmainClass=io.temporal.samples.metrics.MetricsStarter
13 | ```
14 |
15 | 3. See the worker metrics on the exposed Prometheus Scrape Endpoint: [http://localhost:8077/metrics](http://localhost:8077/metrics)
16 |
17 | 4. See the starter metrics on the exposed Prometheus Scrape Endpoint [http://localhost:8078/metrics](http://localhost:8078/metrics)
18 |
19 | 5. Stop the worker and starter
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/metrics/activities/MetricsActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.metrics.activities;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface MetricsActivities {
7 | String performA(String input);
8 |
9 | String performB(String input);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.metrics.workflow;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface MetricsWorkflow {
8 | @WorkflowMethod
9 | String exec(String input);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/metrics/workflow/MetricsWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.metrics.workflow;
2 |
3 | import com.uber.m3.tally.Scope;
4 | import io.temporal.activity.ActivityOptions;
5 | import io.temporal.samples.metrics.activities.MetricsActivities;
6 | import io.temporal.workflow.Workflow;
7 | import java.time.Duration;
8 | import java.util.Collections;
9 |
10 | public class MetricsWorkflowImpl implements MetricsWorkflow {
11 |
12 | private final MetricsActivities activities =
13 | Workflow.newActivityStub(
14 | MetricsActivities.class,
15 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
16 |
17 | @Override
18 | public String exec(String input) {
19 | /*
20 | * Custom metric, we can use child scope and attach workflow_id as it's not attached by default
21 | * like task_queue ,workflow_type, etc
22 | */
23 | Scope scope =
24 | Workflow.getMetricsScope()
25 | .tagged(Collections.singletonMap("workflow_id", Workflow.getInfo().getWorkflowId()));
26 | scope.counter("custom_metric").inc(1);
27 |
28 | String result = activities.performA(input);
29 | Workflow.sleep(Duration.ofSeconds(5));
30 | result += activities.performB(input);
31 |
32 | return result;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneybatch/Account.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneybatch;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface Account {
7 |
8 | void deposit(String accountId, String referenceId, int amountCents);
9 |
10 | void withdraw(String accountId, String referenceId, int amountCents);
11 | }
12 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneybatch/AccountActivityWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneybatch;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 |
8 | public class AccountActivityWorker {
9 |
10 | static final String TASK_QUEUE = "Account";
11 |
12 | @SuppressWarnings("CatchAndPrintStackTrace")
13 | public static void main(String[] args) {
14 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
15 | WorkflowClient client = WorkflowClient.newInstance(service);
16 |
17 | WorkerFactory factory = WorkerFactory.newInstance(client);
18 | Worker worker = factory.newWorker(TASK_QUEUE);
19 |
20 | Account account = new AccountImpl();
21 | worker.registerActivitiesImplementations(account);
22 |
23 | factory.start();
24 | System.out.println("Activity Worker started for task queue: " + TASK_QUEUE);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneybatch/AccountImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneybatch;
2 |
3 | public class AccountImpl implements Account {
4 | @Override
5 | public void deposit(String accountId, String referenceId, int amountCents) {
6 | System.out.printf(
7 | "Deposit to %s of %d cents requested. ReferenceId=%s\n",
8 | accountId, amountCents, referenceId);
9 | // throw new RuntimeException("simulated"); // Uncomment to simulate failure
10 | }
11 |
12 | @Override
13 | public void withdraw(String accountId, String referenceId, int amountCents) {
14 | System.out.printf(
15 | "Withdraw to %s of %d cents requested. ReferenceId=%s\n",
16 | accountId, amountCents, referenceId);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneybatch;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 |
8 | public class AccountTransferWorker {
9 |
10 | @SuppressWarnings("CatchAndPrintStackTrace")
11 | public static void main(String[] args) {
12 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
13 | WorkflowClient client = WorkflowClient.newInstance(service);
14 | WorkerFactory factory = WorkerFactory.newInstance(client);
15 |
16 | Worker worker = factory.newWorker(AccountActivityWorker.TASK_QUEUE);
17 | worker.registerWorkflowImplementationTypes(AccountTransferWorkflowImpl.class);
18 |
19 | factory.start();
20 | System.out.println("Worker started for task queue: " + AccountActivityWorker.TASK_QUEUE);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneybatch/AccountTransferWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneybatch;
2 |
3 | import io.temporal.workflow.QueryMethod;
4 | import io.temporal.workflow.SignalMethod;
5 | import io.temporal.workflow.WorkflowInterface;
6 | import io.temporal.workflow.WorkflowMethod;
7 |
8 | @WorkflowInterface
9 | public interface AccountTransferWorkflow {
10 |
11 | @WorkflowMethod
12 | void deposit(String toAccountId, int batchSize);
13 |
14 | @SignalMethod
15 | void withdraw(String fromAccountId, String referenceId, int amountCents);
16 |
17 | @QueryMethod
18 | int getBalance();
19 |
20 | @QueryMethod
21 | int getCount();
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneytransfer/Account.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneytransfer;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface Account {
7 |
8 | void deposit(String accountId, String referenceId, int amountCents);
9 |
10 | void withdraw(String accountId, String referenceId, int amountCents);
11 | }
12 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneytransfer/AccountActivityWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneytransfer;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 |
8 | public class AccountActivityWorker {
9 |
10 | public static final String TASK_QUEUE = "AccountTransfer";
11 |
12 | @SuppressWarnings("CatchAndPrintStackTrace")
13 | public static void main(String[] args) {
14 | // gRPC stubs wrapper that talks to the local docker instance of temporal service.
15 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
16 | // client that can be used to start and signal workflows
17 | WorkflowClient client = WorkflowClient.newInstance(service);
18 |
19 | // worker factory that can be used to create workers for specific task queues
20 | WorkerFactory factory = WorkerFactory.newInstance(client);
21 | Worker worker = factory.newWorker(TASK_QUEUE);
22 | Account account = new AccountImpl();
23 | worker.registerActivitiesImplementations(account);
24 |
25 | // Start all workers created by this factory.
26 | factory.start();
27 | System.out.println("Activity Worker started for task queue: " + TASK_QUEUE);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneytransfer/AccountImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneytransfer;
2 |
3 | public class AccountImpl implements Account {
4 |
5 | @Override
6 | public void withdraw(String accountId, String referenceId, int amountCents) {
7 | System.out.printf(
8 | "Withdraw to %s of %d cents requested. ReferenceId=%s\n",
9 | accountId, amountCents, referenceId);
10 | }
11 |
12 | @Override
13 | public void deposit(String accountId, String referenceId, int amountCents) {
14 | System.out.printf(
15 | "Deposit to %s of %d cents requested. ReferenceId=%s\n",
16 | accountId, amountCents, referenceId);
17 | // throw new RuntimeException("simulated");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneytransfer;
2 |
3 | import static io.temporal.samples.moneytransfer.AccountActivityWorker.TASK_QUEUE;
4 |
5 | import io.temporal.client.WorkflowClient;
6 | import io.temporal.serviceclient.WorkflowServiceStubs;
7 | import io.temporal.worker.Worker;
8 | import io.temporal.worker.WorkerFactory;
9 |
10 | public class AccountTransferWorker {
11 |
12 | @SuppressWarnings("CatchAndPrintStackTrace")
13 | public static void main(String[] args) {
14 | // Get worker to poll the common task queue.
15 | // gRPC stubs wrapper that talks to the local docker instance of temporal service.
16 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
17 | // client that can be used to start and signal workflows
18 | WorkflowClient client = WorkflowClient.newInstance(service);
19 |
20 | // worker factory that can be used to create workers for specific task queues
21 | WorkerFactory factory = WorkerFactory.newInstance(client);
22 | Worker worker = factory.newWorker(TASK_QUEUE);
23 | worker.registerWorkflowImplementationTypes(AccountTransferWorkflowImpl.class);
24 | // Start all workers created by this factory.
25 | factory.start();
26 | System.out.println("Worker started for task queue: " + TASK_QUEUE);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneytransfer;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface AccountTransferWorkflow {
8 | @WorkflowMethod
9 | void transfer(String fromAccountId, String toAccountId, String referenceId, int amountCents);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneytransfer/AccountTransferWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.moneytransfer;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.workflow.Workflow;
5 | import java.time.Duration;
6 |
7 | public class AccountTransferWorkflowImpl implements AccountTransferWorkflow {
8 |
9 | private final ActivityOptions options =
10 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(5)).build();
11 | private final Account account = Workflow.newActivityStub(Account.class, options);
12 |
13 | @Override
14 | public void transfer(
15 | String fromAccountId, String toAccountId, String referenceId, int amountCents) {
16 | account.withdraw(fromAccountId, referenceId, amountCents);
17 | account.deposit(toAccountId, referenceId, amountCents);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/moneytransfer/README.MD:
--------------------------------------------------------------------------------
1 | The Money Transfer sample has three separate processes.
2 | One to host Workflow Executions, another to host Activity Executions, and the third one to request transfers (start Workflow Executions).
3 |
4 | Start Workflow Worker:
5 |
6 | ```bash
7 | ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountTransferWorker
8 | ```
9 |
10 | Start Activity Worker:
11 |
12 | ```bash
13 | ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountActivityWorker
14 | ```
15 |
16 | Execute once per requested transfer:
17 |
18 | ```bash
19 | ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.TransferRequester
20 | ```
21 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexus.caller;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.samples.nexus.options.ClientOptions;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 | import io.temporal.worker.WorkflowImplementationOptions;
8 | import io.temporal.workflow.NexusServiceOptions;
9 | import java.util.Collections;
10 |
11 | public class CallerWorker {
12 | public static final String DEFAULT_TASK_QUEUE_NAME = "my-caller-workflow-task-queue";
13 |
14 | public static void main(String[] args) {
15 | WorkflowClient client = ClientOptions.getWorkflowClient(args);
16 |
17 | WorkerFactory factory = WorkerFactory.newInstance(client);
18 |
19 | Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
20 | worker.registerWorkflowImplementationTypes(
21 | WorkflowImplementationOptions.newBuilder()
22 | .setNexusServiceOptions(
23 | Collections.singletonMap(
24 | "NexusService",
25 | NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build()))
26 | .build(),
27 | EchoCallerWorkflowImpl.class,
28 | HelloCallerWorkflowImpl.class);
29 |
30 | factory.start();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexus.caller;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface EchoCallerWorkflow {
8 | @WorkflowMethod
9 | String echo(String message);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexus.caller;
2 |
3 | import io.temporal.samples.nexus.service.NexusService;
4 | import io.temporal.workflow.NexusOperationOptions;
5 | import io.temporal.workflow.NexusServiceOptions;
6 | import io.temporal.workflow.Workflow;
7 | import java.time.Duration;
8 |
9 | public class EchoCallerWorkflowImpl implements EchoCallerWorkflow {
10 | NexusService nexusService =
11 | Workflow.newNexusServiceStub(
12 | NexusService.class,
13 | NexusServiceOptions.newBuilder()
14 | .setOperationOptions(
15 | NexusOperationOptions.newBuilder()
16 | .setScheduleToCloseTimeout(Duration.ofSeconds(10))
17 | .build())
18 | .build());
19 |
20 | @Override
21 | public String echo(String message) {
22 | return nexusService.echo(new NexusService.EchoInput(message)).getMessage();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexus.caller;
2 |
3 | import io.temporal.samples.nexus.service.NexusService;
4 | import io.temporal.workflow.WorkflowInterface;
5 | import io.temporal.workflow.WorkflowMethod;
6 |
7 | @WorkflowInterface
8 | public interface HelloCallerWorkflow {
9 | @WorkflowMethod
10 | String hello(String message, NexusService.Language language);
11 | }
12 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexus.caller;
2 |
3 | import io.temporal.samples.nexus.service.NexusService;
4 | import io.temporal.workflow.NexusOperationHandle;
5 | import io.temporal.workflow.NexusOperationOptions;
6 | import io.temporal.workflow.NexusServiceOptions;
7 | import io.temporal.workflow.Workflow;
8 | import java.time.Duration;
9 |
10 | public class HelloCallerWorkflowImpl implements HelloCallerWorkflow {
11 | NexusService nexusService =
12 | Workflow.newNexusServiceStub(
13 | NexusService.class,
14 | NexusServiceOptions.newBuilder()
15 | .setOperationOptions(
16 | NexusOperationOptions.newBuilder()
17 | .setScheduleToCloseTimeout(Duration.ofSeconds(10))
18 | .build())
19 | .build());
20 |
21 | @Override
22 | public String hello(String message, NexusService.Language language) {
23 | NexusOperationHandle handle =
24 | Workflow.startNexusOperation(
25 | nexusService::hello, new NexusService.HelloInput(message, language));
26 | // Optionally wait for the operation to be started. NexusOperationExecution will contain the
27 | // operation token in case this operation is asynchronous.
28 | handle.getExecution().get();
29 | return handle.getResult().get().getMessage();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexus.handler;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.samples.nexus.options.ClientOptions;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 |
8 | public class HandlerWorker {
9 | public static final String DEFAULT_TASK_QUEUE_NAME = "my-handler-task-queue";
10 |
11 | public static void main(String[] args) {
12 | WorkflowClient client = ClientOptions.getWorkflowClient(args);
13 |
14 | WorkerFactory factory = WorkerFactory.newInstance(client);
15 |
16 | Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
17 | worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class);
18 | worker.registerNexusServiceImplementation(new NexusServiceImpl());
19 |
20 | factory.start();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexus.handler;
2 |
3 | import io.temporal.samples.nexus.service.NexusService;
4 | import io.temporal.workflow.WorkflowInterface;
5 | import io.temporal.workflow.WorkflowMethod;
6 |
7 | @WorkflowInterface
8 | public interface HelloHandlerWorkflow {
9 | @WorkflowMethod
10 | NexusService.HelloOutput hello(NexusService.HelloInput input);
11 | }
12 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexus.handler;
2 |
3 | import io.temporal.failure.ApplicationFailure;
4 | import io.temporal.samples.nexus.service.NexusService;
5 |
6 | public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow {
7 | @Override
8 | public NexusService.HelloOutput hello(NexusService.HelloInput input) {
9 | switch (input.getLanguage()) {
10 | case EN:
11 | return new NexusService.HelloOutput("Hello " + input.getName() + " 👋");
12 | case FR:
13 | return new NexusService.HelloOutput("Bonjour " + input.getName() + " 👋");
14 | case DE:
15 | return new NexusService.HelloOutput("Hallo " + input.getName() + " 👋");
16 | case ES:
17 | return new NexusService.HelloOutput("¡Hola! " + input.getName() + " 👋");
18 | case TR:
19 | return new NexusService.HelloOutput("Merhaba " + input.getName() + " 👋");
20 | }
21 | throw ApplicationFailure.newFailure(
22 | "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexus/service/description.md:
--------------------------------------------------------------------------------
1 | ## Service: [NexusService](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java)
2 | - operation: `echo`
3 | - operation: `hello`
4 |
5 | See https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java for Input / Output types.
6 |
7 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexuscancellation/README.MD:
--------------------------------------------------------------------------------
1 | # Nexus Cancellation
2 |
3 | This sample shows how to cancel a Nexus operation from a caller workflow.
4 |
5 | To run this sample, set up your environment following the instructions in the main [Nexus Sample](../nexus/README.md).
6 |
7 | Next, in separate terminal windows:
8 |
9 | ### Nexus handler worker
10 |
11 | ```
12 | ./gradlew -q execute -PmainClass=io.temporal.samples.nexuscancellation.handler.HandlerWorker \
13 | --args="-target-host localhost:7233 -namespace my-target-namespace"
14 | ```
15 |
16 | ### Nexus caller worker
17 |
18 | ```
19 | ./gradlew -q execute -PmainClass=io.temporal.samples.nexuscancellation.caller.CallerWorker \
20 | --args="-target-host localhost:7233 -namespace my-caller-namespace"
21 | ```
22 |
23 | ### Start caller workflow
24 |
25 | ```
26 | ./gradlew -q execute -PmainClass=io.temporal.samples.nexuscancellation.caller.CallerStarter \
27 | --args="-target-host localhost:7233 -namespace my-caller-namespace"
28 | ```
29 |
30 | ### Output
31 |
32 | which should result in:
33 | ```
34 | INFO i.t.s.n.caller.CallerStarter - Started workflow workflowId: 326732dd-a2b1-4de7-9ddd-dcee4f9f0229 runId: d580499f-79d5-461d-bd49-6248b4e522ae
35 | INFO i.t.s.n.caller.CallerStarter - Workflow result: Hallo Nexus 👋
36 | ```
37 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerStarter.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexuscancellation.caller;
2 |
3 | import io.temporal.api.common.v1.WorkflowExecution;
4 | import io.temporal.client.WorkflowClient;
5 | import io.temporal.client.WorkflowOptions;
6 | import io.temporal.samples.nexus.options.ClientOptions;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | public class CallerStarter {
11 | private static final Logger logger = LoggerFactory.getLogger(CallerStarter.class);
12 |
13 | public static void main(String[] args) {
14 | WorkflowClient client = ClientOptions.getWorkflowClient(args);
15 |
16 | WorkflowOptions workflowOptions =
17 | WorkflowOptions.newBuilder().setTaskQueue(CallerWorker.DEFAULT_TASK_QUEUE_NAME).build();
18 | HelloCallerWorkflow helloWorkflow =
19 | client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions);
20 | WorkflowExecution execution = WorkflowClient.start(helloWorkflow::hello, "Nexus");
21 | logger.info(
22 | "Started workflow workflowId: {} runId: {}",
23 | execution.getWorkflowId(),
24 | execution.getRunId());
25 | logger.info("Workflow result: {}", helloWorkflow.hello("Nexus"));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexuscancellation.caller;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.samples.nexus.options.ClientOptions;
5 | import io.temporal.samples.nexus.service.NexusService;
6 | import io.temporal.worker.Worker;
7 | import io.temporal.worker.WorkerFactory;
8 | import io.temporal.worker.WorkflowImplementationOptions;
9 | import io.temporal.workflow.NexusServiceOptions;
10 | import java.util.Collections;
11 |
12 | public class CallerWorker {
13 | public static final String DEFAULT_TASK_QUEUE_NAME = "my-caller-workflow-task-queue";
14 |
15 | public static void main(String[] args) {
16 | WorkflowClient client = ClientOptions.getWorkflowClient(args);
17 |
18 | WorkerFactory factory = WorkerFactory.newInstance(client);
19 |
20 | Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
21 | worker.registerWorkflowImplementationTypes(
22 | WorkflowImplementationOptions.newBuilder()
23 | .setNexusServiceOptions(
24 | Collections.singletonMap(
25 | NexusService.class.getSimpleName(),
26 | NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build()))
27 | .build(),
28 | HelloCallerWorkflowImpl.class);
29 |
30 | factory.start();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexuscancellation.caller;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface HelloCallerWorkflow {
8 | @WorkflowMethod
9 | String hello(String message);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexuscancellation.handler;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.samples.nexus.handler.NexusServiceImpl;
5 | import io.temporal.samples.nexus.options.ClientOptions;
6 | import io.temporal.worker.Worker;
7 | import io.temporal.worker.WorkerFactory;
8 |
9 | public class HandlerWorker {
10 | public static final String DEFAULT_TASK_QUEUE_NAME = "my-handler-task-queue";
11 |
12 | public static void main(String[] args) {
13 | WorkflowClient client = ClientOptions.getWorkflowClient(args);
14 |
15 | WorkerFactory factory = WorkerFactory.newInstance(client);
16 |
17 | Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME);
18 | worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class);
19 | worker.registerNexusServiceImplementation(new NexusServiceImpl());
20 |
21 | factory.start();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexuscancellation.handler;
2 |
3 | import io.temporal.failure.ApplicationFailure;
4 | import io.temporal.samples.nexus.handler.HelloHandlerWorkflow;
5 | import io.temporal.samples.nexus.service.NexusService;
6 | import io.temporal.workflow.Workflow;
7 | import java.time.Duration;
8 |
9 | public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow {
10 | @Override
11 | public NexusService.HelloOutput hello(NexusService.HelloInput input) {
12 | // Sleep for a random duration to simulate some work
13 | Workflow.sleep(Duration.ofSeconds(Workflow.newRandom().nextInt(5)));
14 | switch (input.getLanguage()) {
15 | case EN:
16 | return new NexusService.HelloOutput("Hello " + input.getName() + " 👋");
17 | case FR:
18 | return new NexusService.HelloOutput("Bonjour " + input.getName() + " 👋");
19 | case DE:
20 | return new NexusService.HelloOutput("Hallo " + input.getName() + " 👋");
21 | case ES:
22 | return new NexusService.HelloOutput("¡Hola! " + input.getName() + " 👋");
23 | case TR:
24 | return new NexusService.HelloOutput("Merhaba " + input.getName() + " 👋");
25 | }
26 | throw ApplicationFailure.newFailure(
27 | "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE");
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.nexuscontextpropagation.caller;
2 |
3 | import io.temporal.samples.nexus.caller.EchoCallerWorkflow;
4 | import io.temporal.samples.nexus.service.NexusService;
5 | import io.temporal.workflow.NexusOperationOptions;
6 | import io.temporal.workflow.NexusServiceOptions;
7 | import io.temporal.workflow.Workflow;
8 | import java.time.Duration;
9 | import org.slf4j.MDC;
10 |
11 | public class EchoCallerWorkflowImpl implements EchoCallerWorkflow {
12 | NexusService nexusService =
13 | Workflow.newNexusServiceStub(
14 | NexusService.class,
15 | NexusServiceOptions.newBuilder()
16 | .setOperationOptions(
17 | NexusOperationOptions.newBuilder()
18 | .setScheduleToCloseTimeout(Duration.ofSeconds(10))
19 | .build())
20 | .build());
21 |
22 | @Override
23 | public String echo(String message) {
24 | MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId());
25 | return nexusService.echo(new NexusService.EchoInput(message)).getMessage();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.payloadconverter.cloudevents;
2 |
3 | import io.cloudevents.CloudEvent;
4 | import io.temporal.workflow.QueryMethod;
5 | import io.temporal.workflow.SignalMethod;
6 | import io.temporal.workflow.WorkflowInterface;
7 | import io.temporal.workflow.WorkflowMethod;
8 |
9 | @WorkflowInterface
10 | public interface CEWorkflow {
11 | @WorkflowMethod
12 | void exec(CloudEvent cloudEvent);
13 |
14 | @SignalMethod
15 | void addEvent(CloudEvent cloudEvent);
16 |
17 | @QueryMethod
18 | CloudEvent getLastEvent();
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/CEWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.payloadconverter.cloudevents;
2 |
3 | import io.cloudevents.CloudEvent;
4 | import io.temporal.workflow.Workflow;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class CEWorkflowImpl implements CEWorkflow {
9 |
10 | private List eventList = new ArrayList<>();
11 |
12 | @Override
13 | public void exec(CloudEvent cloudEvent) {
14 |
15 | eventList.add(cloudEvent);
16 |
17 | Workflow.await(() -> eventList.size() == 10);
18 | }
19 |
20 | @Override
21 | public void addEvent(CloudEvent cloudEvent) {
22 | eventList.add(cloudEvent);
23 | }
24 |
25 | @Override
26 | public CloudEvent getLastEvent() {
27 | return eventList.get(eventList.size() - 1);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/payloadconverter/cloudevents/README.md:
--------------------------------------------------------------------------------
1 | # Custom Payload Converter (CloudEvents)
2 |
3 | The sample demonstrates creating and setting a custom Payload Converter.
4 |
5 | ## Running
6 |
7 | 1. Start Temporal Server with "default" namespace enabled.
8 | For example using local Docker:
9 |
10 | ```bash
11 | git clone https://github.com/temporalio/docker-compose.git
12 | cd docker-compose
13 | docker-compose up
14 | ```
15 |
16 | 2. Run the following command to start the sample:
17 |
18 | ```bash
19 | ./gradlew -q execute -PmainClass=io.temporal.samples.payloadconverter.cloudevents.Starter
20 | ```
21 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.payloadconverter.crypto;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface CryptoWorkflow {
8 | @WorkflowMethod
9 | MyCustomer exec(MyCustomer customer);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/payloadconverter/crypto/CryptoWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.payloadconverter.crypto;
2 |
3 | public class CryptoWorkflowImpl implements CryptoWorkflow {
4 | @Override
5 | public MyCustomer exec(MyCustomer customer) {
6 | // if > 18 "approve" otherwise deny
7 | if (customer.getAge() > 18) {
8 | customer.setApproved(true);
9 | } else {
10 | customer.setApproved(false);
11 | }
12 | return customer;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/payloadconverter/crypto/MyCustomer.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.payloadconverter.crypto;
2 |
3 | import com.codingrodent.jackson.crypto.Encrypt;
4 |
5 | public class MyCustomer {
6 | private String name;
7 | private int age;
8 | private boolean approved;
9 |
10 | public MyCustomer() {}
11 |
12 | public MyCustomer(String name, int age) {
13 | this.name = name;
14 | this.age = age;
15 | }
16 |
17 | @Encrypt
18 | public String getName() {
19 | return name;
20 | }
21 |
22 | public void setName(String name) {
23 | this.name = name;
24 | }
25 |
26 | @Encrypt
27 | public int getAge() {
28 | return age;
29 | }
30 |
31 | public void setAge(int age) {
32 | this.age = age;
33 | }
34 |
35 | @Encrypt
36 | public boolean isApproved() {
37 | return approved;
38 | }
39 |
40 | public void setApproved(boolean approved) {
41 | this.approved = approved;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.peractivityoptions;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface FailingActivities {
7 | void activityTypeA();
8 |
9 | void activityTypeB();
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/peractivityoptions/FailingActivitiesImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.peractivityoptions;
2 |
3 | import io.temporal.activity.Activity;
4 |
5 | public class FailingActivitiesImpl implements FailingActivities {
6 | @Override
7 | public void activityTypeA() {
8 | // Get the activity type
9 | String type = Activity.getExecutionContext().getInfo().getActivityType();
10 | // Get the retry attempt
11 | int attempt = Activity.getExecutionContext().getInfo().getAttempt();
12 | // Wrap checked exception and throw
13 | throw Activity.wrap(
14 | new NullPointerException("Activity type: " + type + " attempt times: " + attempt));
15 | }
16 |
17 | @Override
18 | public void activityTypeB() {
19 | // Get the activity type
20 | String type = Activity.getExecutionContext().getInfo().getActivityType();
21 | // Get the retry attempt
22 | int attempt = Activity.getExecutionContext().getInfo().getAttempt();
23 | // Wrap checked exception and throw
24 | throw Activity.wrap(
25 | new NullPointerException("Activity type: " + type + " attempt times: " + attempt));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/peractivityoptions/PerActivityOptionsWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.peractivityoptions;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface PerActivityOptionsWorkflow {
8 | @WorkflowMethod
9 | void execute();
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/peractivityoptions/README.md:
--------------------------------------------------------------------------------
1 | # Per Activity Type Options Sample
2 |
3 | This sample shows how to set per Activity type options via
4 | WorkflowImplementationOptions
5 |
6 | ```bash
7 | ./gradlew -q execute -PmainClass=io.temporal.samples.peractivityoptions.Starter
8 | ```
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/PollingActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface PollingActivities {
7 | String doPoll();
8 | }
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/PollingWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface PollingWorkflow {
8 | @WorkflowMethod
9 | String exec();
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/README.md:
--------------------------------------------------------------------------------
1 | # Polling
2 |
3 | These samples show three different best practices for polling.
4 |
5 | 1. [Frequently Polling Activity](frequent/README.md)
6 | 2. [Infrequently Polling Activity](infrequent/README.md)
7 | 3. [Periodic Polling of a sequence of activities](periodicsequence/README.md)
8 |
9 | The samples are based on [this](https://community.temporal.io/t/what-is-the-best-practice-for-a-polling-activity/328/2) community forum thread.
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/frequent/README.md:
--------------------------------------------------------------------------------
1 | ## Frequent polling
2 |
3 | This sample shows how we can implement frequent polling (1 second or faster) inside our Activity.
4 | The implementation is a loop that polls our service and then sleeps for the poll interval (1 second in the sample).
5 |
6 | To ensure that polling activity is restarted in a timely manner, we make sure that it heartbeats on every iteration.
7 | Note that heartbeating only works if we set the HeartBeatTimeout to a shorter value than the activity
8 | StartToClose timeout.
9 |
10 |
11 | To run this sample:
12 | ```bash
13 | ./gradlew -q execute -PmainClass=io.temporal.samples.polling.frequent.FrequentPollingStarter
14 | ```
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/infrequent/InfrequentPollingActivityImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling.infrequent;
2 |
3 | import io.temporal.activity.Activity;
4 | import io.temporal.samples.polling.PollingActivities;
5 | import io.temporal.samples.polling.TestService;
6 |
7 | public class InfrequentPollingActivityImpl implements PollingActivities {
8 | private TestService service;
9 |
10 | public InfrequentPollingActivityImpl(TestService service) {
11 | this.service = service;
12 | }
13 |
14 | @Override
15 | public String doPoll() {
16 | try {
17 | return service.getServiceResult();
18 | } catch (TestService.TestServiceException e) {
19 | // We want to rethrow the service exception so we can poll via activity retries
20 | throw Activity.wrap(e);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/infrequent/README.md:
--------------------------------------------------------------------------------
1 | ## Infrequent polling
2 |
3 | This sample shows how we can use Activity retries for infrequent polling of a third-party service (for example via REST).
4 | This method can be used for infrequent polls of one minute or slower.
5 |
6 | We utilize activity retries for this option, setting Retries options:
7 | * setBackoffCoefficient to 1
8 | * setInitialInterval to the polling interval (in this sample set to 60 seconds)
9 |
10 | This will allow us to retry our Activity exactly on the set interval.
11 |
12 | To run this sample:
13 | ```bash
14 | ./gradlew -q execute -PmainClass=io.temporal.samples.polling.infrequent.InfrequentPollingStarter
15 | ```
16 |
17 | Since our test service simulates it being "down" for 4 polling attempts and then returns "OK" on the 5th poll attempt, our Workflow is going to perform 4 activity retries with a 60 second poll interval, and then return the service result on the successful 5th attempt.
18 |
19 | Note that individual Activity retries are not recorded in Workflow History, so we this approach we can poll for a very long time without affecting the history size.
20 |
21 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingActivityImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling.periodicsequence;
2 |
3 | import io.temporal.activity.Activity;
4 | import io.temporal.samples.polling.PollingActivities;
5 | import io.temporal.samples.polling.TestService;
6 |
7 | public class PeriodicPollingActivityImpl implements PollingActivities {
8 |
9 | private TestService service;
10 |
11 | public PeriodicPollingActivityImpl(TestService service) {
12 | this.service = service;
13 | }
14 |
15 | @Override
16 | public String doPoll() {
17 | try {
18 | return service.getServiceResult();
19 | } catch (TestService.TestServiceException e) {
20 | // We want to rethrow the service exception so we can poll via activity retries
21 | throw Activity.wrap(e);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/periodicsequence/PeriodicPollingWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling.periodicsequence;
2 |
3 | import io.temporal.samples.polling.PollingWorkflow;
4 | import io.temporal.workflow.ChildWorkflowOptions;
5 | import io.temporal.workflow.Workflow;
6 |
7 | public class PeriodicPollingWorkflowImpl implements PollingWorkflow {
8 |
9 | // Set some periodic poll interval, for sample we set 5 seconds
10 | private int pollingIntervalInSeconds = 5;
11 |
12 | @Override
13 | public String exec() {
14 | PollingChildWorkflow childWorkflow =
15 | Workflow.newChildWorkflowStub(
16 | PollingChildWorkflow.class,
17 | ChildWorkflowOptions.newBuilder().setWorkflowId("ChildWorkflowPoll").build());
18 |
19 | return childWorkflow.exec(pollingIntervalInSeconds);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/periodicsequence/PollingChildWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling.periodicsequence;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface PollingChildWorkflow {
8 | @WorkflowMethod
9 | String exec(int pollingIntervalInSeconds);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/polling/periodicsequence/README.md:
--------------------------------------------------------------------------------
1 | ## Periodic sequence
2 |
3 | This samples shows periodic polling via Child Workflow.
4 |
5 | This is a rare scenario where polling requires execution of a sequence of Activities, or Activity arguments need to change between polling retries.
6 |
7 | For this case we use a Child Workflow to call polling Activities a set number of times in a loop and then periodically calls continue-as-new.
8 |
9 | The Parent Workflow is not aware about the Child Workflow calling continue-as-new and it gets notified when it completes (or fails).
10 |
11 | To run this sample:
12 | ```bash
13 | ./gradlew -q execute -PmainClass=io.temporal.samples.polling.periodicsequence.PeriodicPollingStarter
14 | ```
15 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/FailureRequester.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID;
4 |
5 | import io.temporal.client.WorkflowClient;
6 | import io.temporal.serviceclient.WorkflowServiceStubs;
7 |
8 | /**
9 | * Send signal requesting that an exception thrown from the activity is propagated to the workflow.
10 | */
11 | public class FailureRequester {
12 |
13 | public static void main(String[] args) {
14 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
15 | WorkflowClient client = WorkflowClient.newInstance(service);
16 |
17 | // Note that we use the listener interface that the interceptor registered dynamically, not the
18 | // workflow interface.
19 | RetryOnSignalInterceptorListener workflow =
20 | client.newWorkflowStub(RetryOnSignalInterceptorListener.class, WORKFLOW_ID);
21 |
22 | // Sends "Fail" signal to the workflow.
23 | workflow.fail();
24 |
25 | System.out.println("\"Fail\" signal sent");
26 | System.exit(0);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivity.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface MyActivity {
7 | void execute();
8 | }
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyActivityImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import io.temporal.failure.ApplicationFailure;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | public class MyActivityImpl implements MyActivity {
7 |
8 | /**
9 | * WARNING! Never rely on such shared state in real applications. The activity variables are per
10 | * process and in almost all cases multiple worker processes are used.
11 | */
12 | private final AtomicInteger count = new AtomicInteger();
13 |
14 | /** Sleeps 5 seconds. Fails for 4 first invocations, and then completes. */
15 | @Override
16 | public void execute() {
17 | try {
18 | Thread.sleep(5000);
19 | } catch (InterruptedException e) {
20 | throw new RuntimeException(e);
21 | }
22 | if (count.incrementAndGet() < 5) {
23 | throw ApplicationFailure.newFailure("simulated", "type1");
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface MyWorkflow {
8 |
9 | @WorkflowMethod
10 | void execute();
11 | }
12 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/MyWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.common.RetryOptions;
5 | import io.temporal.workflow.Workflow;
6 | import java.time.Duration;
7 |
8 | public class MyWorkflowImpl implements MyWorkflow {
9 |
10 | private final MyActivity activity =
11 | Workflow.newActivityStub(
12 | MyActivity.class,
13 | ActivityOptions.newBuilder()
14 | .setStartToCloseTimeout(Duration.ofSeconds(30))
15 | // disable server side retries. In most production applications the retries should be
16 | // done for a while before requiring an external operator signal.
17 | .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build())
18 | .build());
19 |
20 | @Override
21 | public void execute() {
22 | activity.execute();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/QueryRequester.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID;
4 |
5 | import io.temporal.client.WorkflowClient;
6 | import io.temporal.serviceclient.WorkflowServiceStubs;
7 |
8 | public class QueryRequester {
9 |
10 | public static void main(String[] args) {
11 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
12 | WorkflowClient client = WorkflowClient.newInstance(service);
13 |
14 | // Note that we use the listener interface that the interceptor registered dynamically, not the
15 | // workflow interface.
16 | RetryOnSignalInterceptorListener workflow =
17 | client.newWorkflowStub(RetryOnSignalInterceptorListener.class, WORKFLOW_ID);
18 |
19 | // Queries workflow.
20 | String status = workflow.getPendingActivitiesStatus();
21 |
22 | System.out.println("Workflow Pending Activities Status:\n\n" + status);
23 | System.exit(0);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/README.MD:
--------------------------------------------------------------------------------
1 | # The Retry On Signal Interceptor
2 |
3 | Demonstrates an interceptor that upon activity failure waits for an external signal that indicates if activity should
4 | fail or retry.
5 |
6 | Starts Worker. The worker upon start initiates a workflow that has an activity that fails on the fist invocation.
7 |
8 | ```bash
9 | ./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker
10 | ```
11 |
12 | Sends Signal to indicate that the activity should be retried.
13 |
14 | ```bash
15 | ./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.RetryRequester
16 | ```
17 |
18 | Sends a signal to propagate the activity failure to the workflow instead of retrying.
19 |
20 | ```bash
21 | ./gradlew -q execute -PmainClass=io.temporal.samples.retryonsignalinterceptor.FailureRequester
22 | ```
23 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalInterceptorListener.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import io.temporal.workflow.QueryMethod;
4 | import io.temporal.workflow.SignalMethod;
5 |
6 | /** Interface used to dynamically register signal and query handlers from the interceptor. */
7 | public interface RetryOnSignalInterceptorListener {
8 |
9 | /** Requests retry of the activities waiting after failure. */
10 | @SignalMethod
11 | void retry();
12 |
13 | /** Requests no more retries of the activities waiting after failure. */
14 | @SignalMethod
15 | void fail();
16 |
17 | /** Returns human status of the pending activities. */
18 | @QueryMethod
19 | String getPendingActivitiesStatus();
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkerInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import io.temporal.common.interceptors.*;
4 |
5 | /** Should be registered through WorkerFactoryOptions. */
6 | public class RetryOnSignalWorkerInterceptor extends WorkerInterceptorBase {
7 | @Override
8 | public WorkflowInboundCallsInterceptor interceptWorkflow(WorkflowInboundCallsInterceptor next) {
9 | return new RetryOnSignalWorkflowInboundCallsInterceptor(next);
10 | }
11 |
12 | @Override
13 | public ActivityInboundCallsInterceptor interceptActivity(ActivityInboundCallsInterceptor next) {
14 | return next;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryOnSignalWorkflowInboundCallsInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import io.temporal.common.interceptors.WorkflowInboundCallsInterceptor;
4 | import io.temporal.common.interceptors.WorkflowInboundCallsInterceptorBase;
5 | import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor;
6 |
7 | public class RetryOnSignalWorkflowInboundCallsInterceptor
8 | extends WorkflowInboundCallsInterceptorBase {
9 |
10 | public RetryOnSignalWorkflowInboundCallsInterceptor(WorkflowInboundCallsInterceptor next) {
11 | super(next);
12 | }
13 |
14 | @Override
15 | public void init(WorkflowOutboundCallsInterceptor outboundCalls) {
16 | super.init(new RetryOnSignalWorkflowOutboundCallsInterceptor(outboundCalls));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/retryonsignalinterceptor/RetryRequester.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.retryonsignalinterceptor;
2 |
3 | import static io.temporal.samples.retryonsignalinterceptor.MyWorkflowWorker.WORKFLOW_ID;
4 |
5 | import io.temporal.client.WorkflowClient;
6 | import io.temporal.serviceclient.WorkflowServiceStubs;
7 |
8 | public class RetryRequester {
9 |
10 | public static void main(String[] args) {
11 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
12 | WorkflowClient client = WorkflowClient.newInstance(service);
13 |
14 | // Note that we use the listener interface that the interceptor registered dynamically, not the
15 | // workflow interface.
16 | RetryOnSignalInterceptorListener workflow =
17 | client.newWorkflowStub(RetryOnSignalInterceptorListener.class, WORKFLOW_ID);
18 |
19 | // Sends "Retry" signal to the workflow.
20 | workflow.retry();
21 |
22 | System.out.println("\"Retry\" signal sent");
23 | System.exit(0);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/safemessagepassing/ClusterManagerWorkflowWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.safemessagepassing;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | public class ClusterManagerWorkflowWorker {
11 | private static final Logger logger = LoggerFactory.getLogger(ClusterManagerWorkflowWorker.class);
12 | static final String TASK_QUEUE = "ClusterManagerWorkflowTaskQueue";
13 | static final String CLUSTER_MANAGER_WORKFLOW_ID = "ClusterManagerWorkflow";
14 |
15 | public static void main(String[] args) {
16 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
17 | WorkflowClient client = WorkflowClient.newInstance(service);
18 | WorkerFactory factory = WorkerFactory.newInstance(client);
19 | final Worker worker = factory.newWorker(TASK_QUEUE);
20 | worker.registerWorkflowImplementationTypes(ClusterManagerWorkflowImpl.class);
21 | worker.registerActivitiesImplementations(new ClusterManagerActivitiesImpl());
22 | factory.start();
23 | logger.info("Worker started for task queue: " + TASK_QUEUE);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/sleepfordays/README.md:
--------------------------------------------------------------------------------
1 | # Sleep for days
2 |
3 | This sample demonstrates how to use Temporal to run a workflow that periodically sleeps for a number of days.
4 |
5 | ## Run the sample
6 |
7 | 1. Start the Worker:
8 |
9 | ```bash
10 | ./gradlew -q execute -PmainClass=io.temporal.samples.sleepfordays.Worker
11 | ```
12 |
13 | 2. Start the Starter
14 |
15 | ```bash
16 | ./gradlew -q execute -PmainClass=io.temporal.samples.sleepfordays.Starter
17 | ```
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivity.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.sleepfordays;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface SendEmailActivity {
7 | void sendEmail(String email);
8 | }
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/sleepfordays/SendEmailActivityImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.sleepfordays;
2 |
3 | public class SendEmailActivityImpl implements SendEmailActivity {
4 | @Override
5 | public void sendEmail(String email) {
6 | System.out.println(email);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.sleepfordays;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.workflow.Promise;
5 | import io.temporal.workflow.Workflow;
6 | import java.time.Duration;
7 |
8 | public class SleepForDaysImpl implements SleepForDaysWorkflow {
9 |
10 | private final SendEmailActivity activity;
11 | private boolean complete = false;
12 |
13 | public SleepForDaysImpl() {
14 | this.activity =
15 | Workflow.newActivityStub(
16 | SendEmailActivity.class,
17 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build());
18 | }
19 |
20 | @Override
21 | public String sleepForDays() {
22 | while (!this.complete) {
23 | activity.sendEmail(String.format("Sleeping for 30 days"));
24 | Promise timer = Workflow.newTimer(Duration.ofDays(30));
25 | Workflow.await(() -> timer.isCompleted() || this.complete);
26 | }
27 |
28 | return "done!";
29 | }
30 |
31 | @Override
32 | public void complete() {
33 | this.complete = true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/sleepfordays/SleepForDaysWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.sleepfordays;
2 |
3 | import io.temporal.workflow.SignalMethod;
4 | import io.temporal.workflow.WorkflowInterface;
5 | import io.temporal.workflow.WorkflowMethod;
6 |
7 | @WorkflowInterface
8 | public interface SleepForDaysWorkflow {
9 | @WorkflowMethod
10 | String sleepForDays();
11 |
12 | @SignalMethod
13 | void complete();
14 | }
15 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/sleepfordays/Starter.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.sleepfordays;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.client.WorkflowOptions;
5 | import io.temporal.client.WorkflowStub;
6 |
7 | public class Starter {
8 |
9 | public static final String TASK_QUEUE = "SleepForDaysTaskQueue";
10 |
11 | public static void main(String[] args) {
12 | // Start a workflow execution.
13 | SleepForDaysWorkflow workflow =
14 | Worker.client.newWorkflowStub(
15 | SleepForDaysWorkflow.class,
16 | WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build());
17 |
18 | // Start the workflow.
19 | WorkflowClient.start(workflow::sleepForDays);
20 |
21 | WorkflowStub stub = WorkflowStub.fromTyped(workflow);
22 |
23 | // Wait for workflow to complete. This will wait indefinitely until a 'complete' signal is sent.
24 | stub.getResult(String.class);
25 | System.exit(0);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/sleepfordays/Worker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.sleepfordays;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.WorkerFactory;
6 |
7 | public class Worker {
8 | public static final String TASK_QUEUE = "SleepForDaysTaskQueue";
9 | public static final WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
10 | public static final WorkflowClient client = WorkflowClient.newInstance(service);
11 | public static final WorkerFactory factory = WorkerFactory.newInstance(client);
12 |
13 | public static void main(String[] args) {
14 | io.temporal.worker.Worker worker = factory.newWorker(TASK_QUEUE);
15 | worker.registerWorkflowImplementationTypes(SleepForDaysImpl.class);
16 | worker.registerActivitiesImplementations(new SendEmailActivityImpl());
17 |
18 | factory.start();
19 | System.out.println("Worker started for task queue: " + TASK_QUEUE);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/ssl/MyWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.ssl;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface MyWorkflow {
8 | @WorkflowMethod
9 | String execute();
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/ssl/MyWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.ssl;
2 |
3 | public class MyWorkflowImpl implements MyWorkflow {
4 | @Override
5 | public String execute() {
6 | return "done";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.terminateworkflow;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface MyWorkflow {
8 | @WorkflowMethod
9 | String execute();
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/terminateworkflow/MyWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.terminateworkflow;
2 |
3 | import io.temporal.workflow.Workflow;
4 | import java.time.Duration;
5 |
6 | public class MyWorkflowImpl implements MyWorkflow {
7 | @Override
8 | public String execute() {
9 | // This workflow just sleeps
10 | Workflow.sleep(Duration.ofSeconds(20));
11 | return "done";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/terminateworkflow/README.md:
--------------------------------------------------------------------------------
1 | # Terminate Workflow execution
2 |
3 | The sample demonstrates how to terminate Workflow Execution using the Client API.
4 |
5 | ```bash
6 | ./gradlew -q execute -PmainClass=io.temporal.samples.terminateworkflow.Starter
7 | ```
8 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivities.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.tracing.workflow;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 |
5 | @ActivityInterface
6 | public interface TracingActivities {
7 | String greet(String name, String language);
8 | }
9 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/tracing/workflow/TracingActivitiesImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.tracing.workflow;
2 |
3 | public class TracingActivitiesImpl implements TracingActivities {
4 | @Override
5 | public String greet(String name, String language) {
6 | String greeting;
7 |
8 | switch (language) {
9 | case "Spanish":
10 | greeting = "Hola " + name;
11 | break;
12 | case "French":
13 | greeting = "Bonjour " + name;
14 | break;
15 | default:
16 | greeting = "Hello " + name;
17 | }
18 |
19 | return greeting;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.tracing.workflow;
2 |
3 | import io.temporal.workflow.WorkflowInterface;
4 | import io.temporal.workflow.WorkflowMethod;
5 |
6 | @WorkflowInterface
7 | public interface TracingChildWorkflow {
8 | @WorkflowMethod
9 | String greet(String name, String language);
10 | }
11 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/tracing/workflow/TracingChildWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.tracing.workflow;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.workflow.Workflow;
5 | import java.time.Duration;
6 |
7 | public class TracingChildWorkflowImpl implements TracingChildWorkflow {
8 | @Override
9 | public String greet(String name, String language) {
10 |
11 | ActivityOptions activityOptions =
12 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build();
13 | TracingActivities activities =
14 | Workflow.newActivityStub(TracingActivities.class, activityOptions);
15 |
16 | return activities.greet(name, language);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.tracing.workflow;
2 |
3 | import io.temporal.workflow.QueryMethod;
4 | import io.temporal.workflow.SignalMethod;
5 | import io.temporal.workflow.WorkflowInterface;
6 | import io.temporal.workflow.WorkflowMethod;
7 |
8 | @WorkflowInterface
9 | public interface TracingWorkflow {
10 |
11 | @WorkflowMethod
12 | String greet(String name);
13 |
14 | @SignalMethod
15 | void setLanguage(String language);
16 |
17 | @QueryMethod
18 | String getLanguage();
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/tracing/workflow/TracingWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.tracing.workflow;
2 |
3 | import io.temporal.workflow.ChildWorkflowOptions;
4 | import io.temporal.workflow.Workflow;
5 |
6 | public class TracingWorkflowImpl implements TracingWorkflow {
7 |
8 | private String language = "English";
9 |
10 | @Override
11 | public String greet(String name) {
12 | ChildWorkflowOptions options =
13 | ChildWorkflowOptions.newBuilder().setWorkflowId("tracingChildWorkflow").build();
14 |
15 | // Get the child workflow stub
16 | TracingChildWorkflow child = Workflow.newChildWorkflowStub(TracingChildWorkflow.class, options);
17 |
18 | // Invoke child sync and return its result
19 | return child.greet(name, language);
20 | }
21 |
22 | @Override
23 | public void setLanguage(String language) {
24 | this.language = language;
25 | }
26 |
27 | @Override
28 | public String getLanguage() {
29 | return language;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.updatabletimer;
2 |
3 | import io.temporal.workflow.QueryMethod;
4 | import io.temporal.workflow.SignalMethod;
5 | import io.temporal.workflow.WorkflowInterface;
6 | import io.temporal.workflow.WorkflowMethod;
7 |
8 | @WorkflowInterface
9 | public interface DynamicSleepWorkflow {
10 | @WorkflowMethod
11 | void execute(long wakeUpTime);
12 |
13 | @SignalMethod
14 | void updateWakeUpTime(long wakeUpTime);
15 |
16 | @QueryMethod
17 | long getWakeUpTime();
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.updatabletimer;
2 |
3 | public class DynamicSleepWorkflowImpl implements DynamicSleepWorkflow {
4 |
5 | private UpdatableTimer timer = new UpdatableTimer();
6 |
7 | @Override
8 | public void execute(long wakeUpTime) {
9 | timer.sleepUntil(wakeUpTime);
10 | }
11 |
12 | @Override
13 | public void updateWakeUpTime(long wakeUpTime) {
14 | timer.updateWakeUpTime(wakeUpTime);
15 | }
16 |
17 | @Override
18 | public long getWakeUpTime() {
19 | return timer.getWakeUpTime();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/updatabletimer/DynamicSleepWorkflowWorker.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.updatabletimer;
2 |
3 | import io.temporal.client.WorkflowClient;
4 | import io.temporal.serviceclient.WorkflowServiceStubs;
5 | import io.temporal.worker.Worker;
6 | import io.temporal.worker.WorkerFactory;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | public class DynamicSleepWorkflowWorker {
11 |
12 | static final String TASK_QUEUE = "TimerUpdate";
13 |
14 | private static final Logger logger = LoggerFactory.getLogger(DynamicSleepWorkflowWorker.class);
15 |
16 | /** Create just one workflow instance for the sake of the sample. */
17 | static final String DYNAMIC_SLEEP_WORKFLOW_ID = "DynamicSleepWorkflow";
18 |
19 | public static void main(String[] args) {
20 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
21 | WorkflowClient client = WorkflowClient.newInstance(service);
22 | WorkerFactory factory = WorkerFactory.newInstance(client);
23 | final Worker worker = factory.newWorker(TASK_QUEUE);
24 | worker.registerWorkflowImplementationTypes(DynamicSleepWorkflowImpl.class);
25 | factory.start();
26 | logger.info("Worker started for task queue: " + TASK_QUEUE);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/updatabletimer/UpdatableTimer.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.updatabletimer;
2 |
3 | import io.temporal.workflow.Workflow;
4 | import java.time.Duration;
5 | import java.time.Instant;
6 | import org.slf4j.Logger;
7 |
8 | public final class UpdatableTimer {
9 |
10 | private final Logger logger = Workflow.getLogger(UpdatableTimer.class);
11 |
12 | private long wakeUpTime;
13 | private boolean wakeUpTimeUpdated;
14 |
15 | public void sleepUntil(long wakeUpTime) {
16 | logger.info("sleepUntil: " + Instant.ofEpochMilli(wakeUpTime));
17 | this.wakeUpTime = wakeUpTime;
18 | while (true) {
19 | wakeUpTimeUpdated = false;
20 | Duration sleepInterval = Duration.ofMillis(this.wakeUpTime - Workflow.currentTimeMillis());
21 | logger.info("Going to sleep for " + sleepInterval);
22 | if (!Workflow.await(sleepInterval, () -> wakeUpTimeUpdated)) {
23 | break;
24 | }
25 | }
26 | logger.info("sleepUntil completed");
27 | }
28 |
29 | public void updateWakeUpTime(long wakeUpTime) {
30 | logger.info("updateWakeUpTime: " + Instant.ofEpochMilli(wakeUpTime));
31 | this.wakeUpTime = wakeUpTime;
32 | this.wakeUpTimeUpdated = true;
33 | }
34 |
35 | public long getWakeUpTime() {
36 | return wakeUpTime;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/io/temporal/samples/updatabletimer/WakeUpTimeUpdater.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.updatabletimer;
2 |
3 | import static io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker.DYNAMIC_SLEEP_WORKFLOW_ID;
4 |
5 | import io.temporal.client.WorkflowClient;
6 | import io.temporal.serviceclient.WorkflowServiceStubs;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | public class WakeUpTimeUpdater {
11 |
12 | private static final Logger logger = LoggerFactory.getLogger(WakeUpTimeUpdater.class);
13 |
14 | public static void main(String[] args) {
15 | WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
16 | WorkflowClient client = WorkflowClient.newInstance(service);
17 |
18 | // Create a stub that points to an existing workflow with the given ID
19 | DynamicSleepWorkflow workflow =
20 | client.newWorkflowStub(DynamicSleepWorkflow.class, DYNAMIC_SLEEP_WORKFLOW_ID);
21 |
22 | // signal workflow about the wake up time change
23 | workflow.updateWakeUpTime(System.currentTimeMillis() + 10000);
24 | logger.info("Updated wake up time to 10 seconds from now");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/resources/dsl/sampleflow.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "sampleFlow",
3 | "name": "Sample Flow One",
4 | "description": "Sample Flow Definition",
5 | "actions": [
6 | {
7 | "action": "One",
8 | "retries": 10,
9 | "startToCloseSec": 3
10 | },
11 | {
12 | "action": "Two",
13 | "retries": 8,
14 | "startToCloseSec": 3
15 | },
16 | {
17 | "action": "Three",
18 | "retries": 10,
19 | "startToCloseSec": 4
20 | },
21 | {
22 | "action": "Four",
23 | "retries": 9,
24 | "startToCloseSec": 5
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/core/src/test/java/io/temporal/samples/asyncchild/AsyncChildTest.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.asyncchild;
2 |
3 | import static org.junit.Assert.assertNotNull;
4 |
5 | import io.temporal.api.common.v1.WorkflowExecution;
6 | import io.temporal.client.WorkflowOptions;
7 | import io.temporal.testing.TestWorkflowRule;
8 | import org.junit.Rule;
9 | import org.junit.Test;
10 |
11 | public class AsyncChildTest {
12 |
13 | @Rule
14 | public TestWorkflowRule testWorkflowRule =
15 | TestWorkflowRule.newBuilder()
16 | .setWorkflowTypes(ParentWorkflowImpl.class, ChildWorkflowImpl.class)
17 | .build();
18 |
19 | @Test
20 | public void testAsyncChildWorkflow() {
21 | ParentWorkflow parentWorkflow =
22 | testWorkflowRule
23 | .getWorkflowClient()
24 | .newWorkflowStub(
25 | ParentWorkflow.class,
26 | WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
27 |
28 | WorkflowExecution childExecution = parentWorkflow.executeParent();
29 |
30 | assertNotNull(childExecution);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/core/src/test/java/io/temporal/samples/getresultsasync/GetResultsAsyncTest.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.getresultsasync;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import io.temporal.client.WorkflowOptions;
7 | import io.temporal.client.WorkflowStub;
8 | import io.temporal.testing.TestWorkflowRule;
9 | import java.util.concurrent.CompletableFuture;
10 | import org.junit.Rule;
11 | import org.junit.Test;
12 |
13 | public class GetResultsAsyncTest {
14 |
15 | @Rule
16 | public TestWorkflowRule testWorkflowRule =
17 | TestWorkflowRule.newBuilder().setWorkflowTypes(MyWorkflowImpl.class).build();
18 |
19 | @Test
20 | public void testGetResultsAsync() throws Exception {
21 |
22 | WorkflowStub workflowStub =
23 | testWorkflowRule
24 | .getWorkflowClient()
25 | .newUntypedWorkflowStub(
26 | "MyWorkflow",
27 | WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
28 |
29 | workflowStub.start(5);
30 |
31 | CompletableFuture completableFuture = workflowStub.getResultAsync(String.class);
32 |
33 | String result = completableFuture.get();
34 | assertNotNull(result);
35 | assertEquals("woke up after 5 seconds", result);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/test/java/io/temporal/samples/hello/HelloActivityExclusiveChoiceJUnit5Test.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.hello;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import io.temporal.testing.TestWorkflowExtension;
6 | import org.junit.jupiter.api.Test;
7 | import org.junit.jupiter.api.extension.RegisterExtension;
8 |
9 | /** Unit test for {@link HelloActivityExclusiveChoice}. Doesn't use an external Temporal service. */
10 | public class HelloActivityExclusiveChoiceJUnit5Test {
11 |
12 | @RegisterExtension
13 | public static final TestWorkflowExtension testWorkflowExtension =
14 | TestWorkflowExtension.newBuilder()
15 | .setWorkflowTypes(HelloActivityExclusiveChoice.PurchaseFruitsWorkflowImpl.class)
16 | .setActivityImplementations(new HelloActivityExclusiveChoice.OrderFruitsActivitiesImpl())
17 | .build();
18 |
19 | @Test
20 | public void testWorkflow(HelloActivityExclusiveChoice.PurchaseFruitsWorkflow workflow) {
21 | // Execute a workflow waiting for it to complete.
22 | HelloActivityExclusiveChoice.ShoppingList shoppingList =
23 | new HelloActivityExclusiveChoice.ShoppingList();
24 | shoppingList.addFruitOrder(HelloActivityExclusiveChoice.Fruits.APPLE, 10);
25 | StringBuilder orderResults = workflow.orderFruit(shoppingList);
26 | assertEquals("Ordered 10 Apples...", orderResults.toString());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/test/java/io/temporal/samples/hello/HelloSideEffectTest.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.hello;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import io.temporal.client.WorkflowOptions;
6 | import io.temporal.testing.TestWorkflowRule;
7 | import org.junit.Rule;
8 | import org.junit.Test;
9 |
10 | public class HelloSideEffectTest {
11 |
12 | @Rule
13 | public TestWorkflowRule testWorkflowRule =
14 | TestWorkflowRule.newBuilder()
15 | .setWorkflowTypes(HelloSideEffect.SideEffectWorkflowImpl.class)
16 | .setActivityImplementations(new HelloSideEffect.SideEffectActivitiesImpl())
17 | .build();
18 |
19 | @Test
20 | public void testSideffectsWorkflow() {
21 | // Get a workflow stub using the same task queue the worker uses.
22 | HelloSideEffect.SideEffectWorkflow workflow =
23 | testWorkflowRule
24 | .getWorkflowClient()
25 | .newWorkflowStub(
26 | HelloSideEffect.SideEffectWorkflow.class,
27 | WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
28 | // Execute a workflow waiting for it to complete.
29 | String result = workflow.execute();
30 | // make sure the result is same as the query result after workflow completion
31 | assertEquals(result, workflow.getResult());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/test/java/io/temporal/samples/hello/HelloWorkflowTimerTest.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.hello;
2 |
3 | import io.temporal.client.WorkflowOptions;
4 | import io.temporal.testing.TestWorkflowRule;
5 | import org.junit.Assert;
6 | import org.junit.Rule;
7 | import org.junit.Test;
8 |
9 | public class HelloWorkflowTimerTest {
10 | @Rule
11 | public TestWorkflowRule testWorkflowRule =
12 | TestWorkflowRule.newBuilder()
13 | .setWorkflowTypes(
14 | HelloWorkflowTimer.WorkflowWithTimerImpl.class,
15 | HelloWorkflowTimer.WorkflowWithTimerChildWorkflowImpl.class)
16 | .setActivityImplementations(new HelloWorkflowTimer.WorkflowWithTimerActivitiesImpl())
17 | .build();
18 |
19 | @Test
20 | public void testWorkflowTimer() {
21 | HelloWorkflowTimer.WorkflowWithTimer workflow =
22 | testWorkflowRule
23 | .getWorkflowClient()
24 | .newWorkflowStub(
25 | HelloWorkflowTimer.WorkflowWithTimer.class,
26 | WorkflowOptions.newBuilder()
27 | .setWorkflowId("WorkflowWithTimerTestId")
28 | .setTaskQueue(testWorkflowRule.getTaskQueue())
29 | .build());
30 |
31 | String result = workflow.execute("test input");
32 | Assert.assertEquals("Workflow timer fired while activities were executing.", result);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/test/java/io/temporal/samples/polling/FrequentPollingTest.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import io.temporal.client.WorkflowOptions;
6 | import io.temporal.samples.polling.frequent.FrequentPollingActivityImpl;
7 | import io.temporal.samples.polling.frequent.FrequentPollingWorkflowImpl;
8 | import io.temporal.testing.TestWorkflowRule;
9 | import org.junit.Rule;
10 | import org.junit.Test;
11 |
12 | public class FrequentPollingTest {
13 | @Rule
14 | public TestWorkflowRule testWorkflowRule =
15 | TestWorkflowRule.newBuilder()
16 | .setWorkflowTypes(FrequentPollingWorkflowImpl.class)
17 | .setActivityImplementations(new FrequentPollingActivityImpl(new TestService()))
18 | .build();
19 |
20 | @Test
21 | public void testInfrequentPoll() {
22 | PollingWorkflow workflow =
23 | testWorkflowRule
24 | .getWorkflowClient()
25 | .newWorkflowStub(
26 | PollingWorkflow.class,
27 | WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
28 |
29 | assertEquals("OK", workflow.exec());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/test/java/io/temporal/samples/polling/InfrequentPollingTest.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import io.temporal.client.WorkflowOptions;
6 | import io.temporal.samples.polling.infrequent.InfrequentPollingActivityImpl;
7 | import io.temporal.samples.polling.infrequent.InfrequentPollingWorkflowImpl;
8 | import io.temporal.testing.TestWorkflowRule;
9 | import org.junit.Rule;
10 | import org.junit.Test;
11 |
12 | public class InfrequentPollingTest {
13 | @Rule
14 | public TestWorkflowRule testWorkflowRule =
15 | TestWorkflowRule.newBuilder()
16 | .setWorkflowTypes(InfrequentPollingWorkflowImpl.class)
17 | .setActivityImplementations(new InfrequentPollingActivityImpl(new TestService()))
18 | .build();
19 |
20 | @Test
21 | public void testInfrequentPoll() {
22 | PollingWorkflow workflow =
23 | testWorkflowRule
24 | .getWorkflowClient()
25 | .newWorkflowStub(
26 | PollingWorkflow.class,
27 | WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
28 |
29 | assertEquals("OK", workflow.exec());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/test/java/io/temporal/samples/polling/PeriodicPollingTest.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.polling;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import io.temporal.client.WorkflowOptions;
6 | import io.temporal.samples.polling.periodicsequence.PeriodicPollingActivityImpl;
7 | import io.temporal.samples.polling.periodicsequence.PeriodicPollingChildWorkflowImpl;
8 | import io.temporal.samples.polling.periodicsequence.PeriodicPollingWorkflowImpl;
9 | import io.temporal.testing.TestWorkflowRule;
10 | import org.junit.Rule;
11 | import org.junit.Test;
12 |
13 | public class PeriodicPollingTest {
14 | @Rule
15 | public TestWorkflowRule testWorkflowRule =
16 | TestWorkflowRule.newBuilder()
17 | .setWorkflowTypes(
18 | PeriodicPollingWorkflowImpl.class, PeriodicPollingChildWorkflowImpl.class)
19 | .setActivityImplementations(new PeriodicPollingActivityImpl(new TestService()))
20 | .build();
21 |
22 | @Test
23 | public void testInfrequentPoll() {
24 | PollingWorkflow workflow =
25 | testWorkflowRule
26 | .getWorkflowClient()
27 | .newWorkflowStub(
28 | PollingWorkflow.class,
29 | WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
30 |
31 | assertEquals("OK", workflow.exec());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/test/resources/dsl/sampleflow.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "sampleFlow",
3 | "name": "Sample Flow One",
4 | "description": "Sample Flow Definition",
5 | "actions": [
6 | {
7 | "action": "One",
8 | "retries": 10,
9 | "startToCloseSec": 3
10 | },
11 | {
12 | "action": "Two",
13 | "retries": 8,
14 | "startToCloseSec": 3
15 | },
16 | {
17 | "action": "Three",
18 | "retries": 10,
19 | "startToCloseSec": 4
20 | },
21 | {
22 | "action": "Four",
23 | "retries": 9,
24 | "startToCloseSec": 5
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/docker/github/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM eclipse-temurin:11-focal
2 |
3 | # Git is needed in order to update the dls submodule
4 | RUN apt-get update && apt-get install -y wget protobuf-compiler git
5 |
6 | RUN mkdir /temporal-java-samples
7 | WORKDIR /temporal-java-samples
8 |
--------------------------------------------------------------------------------
/docker/github/README.md:
--------------------------------------------------------------------------------
1 | # Using Github Actions
2 |
3 | Github action simply runs Docker containers. So it is easy to perform the
4 | same build locally that Github will do. To handle this, there are
5 | two different docker-compose files: one for Github and one for local.
6 | The Dockerfile is the same for both.
7 |
8 | ## Testing the build locally
9 | To run the build locally, start from the root folder of this repo and run the following command:
10 | ```bash
11 | docker-compose -f docker/github/docker-compose.yaml run unit-test
12 | ```
13 |
14 | Note that Github action will run basically the same commands.
15 |
16 | ## Testing the build in Github Actions
17 | Creating a PR against the main branch will trigger the Github action.
18 |
--------------------------------------------------------------------------------
/docker/github/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: '3.5'
2 |
3 | services:
4 | unit-test:
5 | build:
6 | context: ../../
7 | dockerfile: ./docker/github/Dockerfile
8 | command: "./gradlew --no-daemon test"
9 | environment:
10 | - "USER=unittest"
11 | volumes:
12 | - "../../:/temporal-java-samples"
13 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | springBootPluginVersion=2.7.13
2 |
3 | # use this for spring boot 3 support
4 | #springBootPluginVersion=3.2.0
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/temporalio/samples-java/c4217c9ce2a3a2e3567d714f4a28cc2ee8dc2048/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'temporal-java-samples'
2 | include 'core'
3 | include 'springboot'
4 | include 'springboot-basic'
5 |
--------------------------------------------------------------------------------
/springboot-basic/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'org.springframework.boot'
2 |
3 | dependencies {
4 | implementation "org.springframework.boot:spring-boot-starter-web"
5 | implementation "org.springframework.boot:spring-boot-starter-thymeleaf"
6 | implementation "org.springframework.boot:spring-boot-starter-actuator"
7 | implementation "io.temporal:temporal-spring-boot-starter:$javaSDKVersion"
8 | testImplementation "org.springframework.boot:spring-boot-starter-test"
9 | runtimeOnly "io.micrometer:micrometer-registry-prometheus"
10 | dependencies {
11 | errorproneJavac('com.google.errorprone:javac:9+181-r4173-1')
12 | if (JavaVersion.current().isJava11Compatible()) {
13 | errorprone('com.google.errorprone:error_prone_core:2.28.0')
14 | } else {
15 | errorprone('com.google.errorprone:error_prone_core:2.28.0')
16 | }
17 | }
18 | }
19 |
20 | bootJar {
21 | enabled = false
22 | }
23 |
24 | jar {
25 | enabled = true
26 | }
--------------------------------------------------------------------------------
/springboot-basic/src/main/java/io/temporal/samples/springboot/TemporalSpringbootSamplesApplication.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.springboot;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class TemporalSpringbootSamplesApplication {
8 | public static void main(String[] args) {
9 | SpringApplication.run(TemporalSpringbootSamplesApplication.class, args).start();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivity.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.springboot.hello;
2 |
3 | import io.temporal.activity.ActivityInterface;
4 | import io.temporal.samples.springboot.hello.model.Person;
5 |
6 | @ActivityInterface
7 | public interface HelloActivity {
8 | String hello(Person person);
9 | }
10 |
--------------------------------------------------------------------------------
/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloActivityImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.springboot.hello;
2 |
3 | import io.temporal.samples.springboot.hello.model.Person;
4 | import io.temporal.spring.boot.ActivityImpl;
5 | import org.springframework.beans.factory.annotation.Value;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | @ActivityImpl(taskQueues = "HelloSampleTaskQueue")
10 | public class HelloActivityImpl implements HelloActivity {
11 | @Value("${samples.data.language}")
12 | private String language;
13 |
14 | @Override
15 | public String hello(Person person) {
16 | String greeting = language.equals("spanish") ? "Hola " : "Hello ";
17 | return greeting + person.getFirstName() + " " + person.getLastName() + "!";
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflow.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.springboot.hello;
2 |
3 | import io.temporal.samples.springboot.hello.model.Person;
4 | import io.temporal.workflow.WorkflowInterface;
5 | import io.temporal.workflow.WorkflowMethod;
6 |
7 | @WorkflowInterface
8 | public interface HelloWorkflow {
9 | @WorkflowMethod
10 | String sayHello(Person person);
11 | }
12 |
--------------------------------------------------------------------------------
/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/HelloWorkflowImpl.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.springboot.hello;
2 |
3 | import io.temporal.activity.ActivityOptions;
4 | import io.temporal.samples.springboot.hello.model.Person;
5 | import io.temporal.spring.boot.WorkflowImpl;
6 | import io.temporal.workflow.Workflow;
7 | import java.time.Duration;
8 |
9 | @WorkflowImpl(taskQueues = "HelloSampleTaskQueue")
10 | public class HelloWorkflowImpl implements HelloWorkflow {
11 |
12 | private HelloActivity activity =
13 | Workflow.newActivityStub(
14 | HelloActivity.class,
15 | ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());
16 |
17 | @Override
18 | public String sayHello(Person person) {
19 | return activity.hello(person);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/README.md:
--------------------------------------------------------------------------------
1 | # SpringBoot Hello Sample
2 |
3 | 1. Start SpringBoot from main samples repo directory:
4 |
5 | ./gradlew :springboot-basic:bootRun
6 |
7 | 2. In your browser navigate to:
8 |
9 | http://localhost:3030/hello
10 |
11 | Enter in first and last name in the form then click on Run Workflow
12 | to start workflow execution. Page will be updated to show the workflow
13 | execution results (the greeting).
14 |
15 | You can try changing the language setting in [application.yaml](../../../../../../resources/application.yaml) file
16 | from "english" to "spanish" to get the greeting result in Spanish.
--------------------------------------------------------------------------------
/springboot-basic/src/main/java/io/temporal/samples/springboot/hello/model/Person.java:
--------------------------------------------------------------------------------
1 | package io.temporal.samples.springboot.hello.model;
2 |
3 | public class Person {
4 | private String firstName;
5 | private String lastName;
6 |
7 | public Person() {}
8 |
9 | public Person(String firstName, String lastName) {
10 | this.firstName = firstName;
11 | this.lastName = lastName;
12 | }
13 |
14 | public String getFirstName() {
15 | return firstName;
16 | }
17 |
18 | public void setFirstName(String firstName) {
19 | this.firstName = firstName;
20 | }
21 |
22 | public String getLastName() {
23 | return lastName;
24 | }
25 |
26 | public void setLastName(String lastName) {
27 | this.lastName = lastName;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/springboot-basic/src/main/resources/application-tc.yaml:
--------------------------------------------------------------------------------
1 | spring.temporal:
2 | namespace: # https://docs.temporal.io/cloud/#temporal-cloud-namespace-id
3 | connection:
4 | target: .tmprl.cloud:7233
5 | mtls:
6 | key-file: /path/to/key.key
7 | cert-chain-file: /path/to/cert.pem
8 |
9 | # more configuration options https://github.com/temporalio/sdk-java/tree/master/temporal-spring-boot-autoconfigure#mtls
--------------------------------------------------------------------------------
/springboot-basic/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 3030
3 | spring:
4 | main:
5 | allow-bean-definition-overriding: true
6 | application:
7 | name: temporal-samples
8 | # temporal specific configs
9 | temporal:
10 | namespace: default
11 | connection:
12 | target: 127.0.0.1:7233
13 | workersAutoDiscovery:
14 | packages: io.temporal.samples.springboot
15 | # specific for samples
16 | samples:
17 | data:
18 | language: english
19 |
--------------------------------------------------------------------------------
/springboot-basic/src/main/resources/static/js/samplessse.js:
--------------------------------------------------------------------------------
1 | $( document ).ready(function() {
2 |
3 | var sse = $.SSE('/kafka-messages', {
4 | onMessage: function(e){
5 | console.log(e);
6 | $('#kafka-messages tr:last').after('
In this sample we show how to create a custom Actuator Endpoint showing Worker Info.
10 |
11 |
12 |
Spring Actuator allows
13 | us to create custom endpoints. This sample shows how to create a Worker Info custom endpoint that shows registered Workflow and Activity impls per task queue.