|
1 | 1 | # Java Temporal Samples |
2 | 2 | These samples demonstrate various capabilities of Java Temporal client and server. You can learn more about Temporal at: |
| 3 | +* [temporal.io](https://temporal.io) |
3 | 4 | * [Temporal Service](https://github.com/temporalio/temporal) |
4 | 5 | * [Temporal Java Client](https://github.com/temporalio/temporal-java-sdk) |
5 | 6 | * [Go Temporal Client](https://github.com/temporalio/temporal-go-sdk) |
6 | 7 |
|
7 | | -## Overview of the Samples |
| 8 | +## Setup |
8 | 9 |
|
9 | | -* **HelloWorld Samples** |
| 10 | +### macOS Specific |
| 11 | +Due to issues with default hostname resolution |
| 12 | +(see [this StackOverflow question](https://stackoverflow.com/questions/33289695/inetaddress-getlocalhost-slow-to-run-30-seconds) for more details), |
| 13 | +macOS Users may see gRPC `DEADLINE_EXCEEDED` errors when running the samples or any other gRPC related code. |
10 | 14 |
|
11 | | - The following samples demonstrate: |
| 15 | +To solve the problem add the following entries to your `/etc/hosts` file (where my-macbook is your hostname): |
12 | 16 |
|
13 | | - * **HelloActivity**: a single activity workflow |
14 | | - * **HelloActivityRetry**: how to retry an activity |
15 | | - * **HelloAsync**: how to call activities asynchronously and wait for them using Promises |
16 | | - * **HelloAsyncLambda**: how to run part of a workflow asynchronously in a separate task (thread) |
17 | | - * **HelloAsyncActivityCompletion**: an asynchronous activity implementation |
18 | | - * **HelloChild**: a child workflow |
19 | | - * **HelloException**: exception propagation and wrapping |
20 | | - * **HelloQuery**: a query |
21 | | - * **HelloSignal**: sending and handling a signal |
22 | | - * **HelloPeriodic**: a sample workflow that executes an activity periodically forever |
23 | | - |
24 | | -* **FileProcessing** demonstrates task routing features. The sample workflow downloads a file, processes it, and uploads |
25 | | - the result to a destination. The first activity can be picked up by any worker. However, the second and third activities |
26 | | - must be executed on the same host as the first one. |
| 17 | +```conf |
| 18 | +127.0.0.1 my-macbook |
| 19 | +::1 my-macbook |
| 20 | +``` |
27 | 21 |
|
28 | | -## Get the Samples |
| 22 | +### Get the Samples |
29 | 23 |
|
30 | 24 | Run the following commands: |
31 | 25 |
|
32 | | - git clone https://github.com/temporalio/temporal-java-samples |
33 | | - cd temporal-java-samples |
| 26 | + git clone https://github.com/temporalio/java-samples |
| 27 | + cd java-samples |
| 28 | + |
| 29 | +### Build the Samples |
34 | 30 |
|
35 | | -## Import into IntelliJ |
| 31 | + ./gradlew build |
| 32 | + |
| 33 | +### Import into IntelliJ |
36 | 34 |
|
37 | 35 | In the IntelliJ user interface, navigate to **File**->**New**->**Project from Existing Sources**. |
38 | 36 |
|
39 | 37 | Select the cloned directory. In the **Import Project page**, select **Import project from external model**, |
40 | 38 | choose **Gradle** and then click **Next**->**Finish**. |
41 | 39 |
|
42 | | -## Build the Samples |
43 | | - |
44 | | - ./gradlew build |
45 | | - |
46 | | -## Run Temporal Server |
| 40 | +### Run Temporal Server |
47 | 41 |
|
48 | | -Run Temporal Server using Docker Compose: |
| 42 | +Samples require Temporal service to run. We recommend a locally running version of Temporal Server |
| 43 | +managed through [Docker Compose](https://docs.docker.com/compose/gettingstarted/): |
49 | 44 |
|
50 | | - curl -L https://github.com/temporalio/temporal/releases/download/v0.26.0/docker.tar.gz | tar -xz --strip-components 1 docker/docker-compose.yml |
| 45 | + curl -L https://github.com/temporalio/temporal/releases/latest/download/docker.tar.gz | tar -xz --strip-components 1 docker/docker-compose.yml |
51 | 46 | docker-compose up |
52 | 47 |
|
53 | 48 | If this does not work, see the instructions for running Temporal Server at https://github.com/temporalio/temporal/blob/master/README.md. |
54 | 49 |
|
55 | | -## See Temporal UI (Not Available yet!) |
| 50 | +## See Temporal UI |
56 | 51 |
|
57 | 52 | The Temporal Server running in a docker container includes a Web UI. |
58 | 53 |
|
59 | 54 | Connect to [http://localhost:8088](http://localhost:8088). |
60 | 55 |
|
61 | | -Enter the *sample* domain. You'll see a "No Results" page. After running any sample, change the |
62 | | -filter in the |
63 | | -top right corner from "Open" to "Closed" to see the list of the completed workflows. |
64 | | - |
65 | 56 | Click on a *RUN ID* of a workflow to see more details about it. Try different view formats to get a different level |
66 | 57 | of details about the execution history. |
67 | 58 |
|
68 | | -## Install Temporal CLI |
| 59 | +## Install Temporal CLI (tctl) |
69 | 60 |
|
70 | | -[Command Line Interface Documentation](https://docs.temporal.io/docs/08_running_temporal/02_cli) |
| 61 | +[Command Line Interface Documentation](https://docs.temporal.io/docs/tctl) |
71 | 62 |
|
72 | | -## Run the samples |
| 63 | +## Samples |
73 | 64 |
|
74 | 65 | Each sample has specific requirements for running it. The following sections contain information about |
75 | 66 | how to run each of the samples after you've built them using the preceding instructions. |
76 | 67 |
|
77 | | -Don't forget to check unit tests found under src/test/java! |
78 | | - |
79 | | -### Hello World |
80 | | - |
81 | | -To run the hello world samples: |
82 | | - |
83 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivity |
84 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivityRetry |
85 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsync |
86 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsyncActivityCompletion |
87 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsyncLambda |
88 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloChild |
89 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloException |
90 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPeriodic |
91 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloCron |
92 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloQuery |
93 | | - ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignal |
| 68 | +Don't forget to check unit tests found under [src/test/java](https://github.com/temporalio/java-samples/tree/master/src/test/java/io/temporal/samples)! |
| 69 | + |
| 70 | +### HelloWorld |
| 71 | + |
| 72 | +Each Hello World sample demonstrates one feature of the SDK in a single file. Note that single file format is |
| 73 | +used for sample brevity and is not something we recommend for real applications. |
| 74 | + |
| 75 | + * **[HelloActivity](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloActivity.java)**: a single activity workflow |
| 76 | + * **[HelloActivityRetry](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java)**: how to retry an activity |
| 77 | + * **[HelloAsync](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloAsync.java)**: how to call activities asynchronously and wait for them using Promises |
| 78 | + * **[HelloAsyncActivityCompletion](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java)**: an asynchronous activity implementation |
| 79 | + * **[HelloAsyncLambda](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloAsyncLambda.java)**: how to run part of a workflow asynchronously in a separate task (thread) |
| 80 | + * **[HelloCancellationScope](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloCancellationScope.java)**: how to explicitly cancel parts of a workflow |
| 81 | + * **[HelloChild](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloChild.java)**: a child workflow |
| 82 | + * **[HelloCron](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloCron.java)**: a workflow that is executed according to a cron schedule |
| 83 | + * **[HelloPeriodic](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloPeriodic.java)**: a workflow that executes some logic periodically |
| 84 | + * **[HelloException](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloException.java)**: exception propagation and wrapping |
| 85 | + * **[HelloPolymorphicActivity](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java)**: activities that extend a common interface |
| 86 | + * **[HelloQuery](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloQuery.java)**: demonstrates how to query a state of a single workflow |
| 87 | + * **[HelloSignal](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloSignal.java)**: sending and handling a signal |
| 88 | + * **[HelloSaga](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloSaga.java)**: SAGA pattern support |
| 89 | + * **[HelloSearchAttributes](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloSearchAttributes.java)**: Custom search attributes that can be used to find workflows using predicates |
| 90 | + |
| 91 | + To run the hello world samples: |
| 92 | + |
| 93 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivity |
| 94 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivityRetry |
| 95 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsync |
| 96 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsyncActivityCompletion |
| 97 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsyncLambda |
| 98 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloCancellationScope |
| 99 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloChild |
| 100 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloCron |
| 101 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloException |
| 102 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPeriodic |
| 103 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPolymorphicActivity |
| 104 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloQuery |
| 105 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSaga |
| 106 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignal |
| 107 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSearchAttributes |
94 | 108 |
|
95 | 109 | ### File Processing |
96 | | - |
97 | | -This sample has two executables. Execute each command in a separate terminal window. The first command |
| 110 | +[FileProcessing](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/fileprocessing) |
| 111 | +demonstrates task routing features. The sample workflow downloads a file, processes it, and uploads the result to a destination. Any worker can pick up the first activity. However, the second and third activity must be executed on the same host as the first one. |
| 112 | + |
| 113 | +The sample has two executables. Execute each command in a separate terminal window. The first command |
98 | 114 | runs the worker that hosts the workflow and activities implementation. To demonstrate that activities |
99 | | -execute together, we recommend that you run more than one instance of this worker. |
| 115 | +execute together, we recommend running more than one instance of this worker. |
100 | 116 |
|
101 | 117 | ./gradlew -q execute -PmainClass=io.temporal.samples.fileprocessing.FileProcessingWorker |
102 | 118 |
|
103 | 119 | The second command starts workflows. Each invocation starts a new workflow execution. |
104 | 120 |
|
105 | 121 | ./gradlew -q execute -PmainClass=io.temporal.samples.fileprocessing.FileProcessingStarter |
106 | 122 |
|
107 | | -### Trip Booking |
108 | | - |
109 | | -Temporal implementation of the [Camunda BPMN trip booking example](https://github.com/berndruecker/trip-booking-saga-java) |
| 123 | +### Booking SAGA |
110 | 124 |
|
111 | | -Demonstrates Temporal approach to SAGA. |
| 125 | +[Booking SAGA](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/bookingsaga) |
| 126 | +is a Temporal take on Camunda BPMN trip booking example. |
112 | 127 |
|
113 | 128 | To run: |
114 | 129 |
|
115 | 130 | ./gradlew -q execute -PmainClass=io.temporal.samples.bookingsaga.TripBookingSaga |
| 131 | + |
| 132 | +### Money Transfer |
| 133 | + |
| 134 | +Basic [Money Transfer](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/moneytransfer) example. |
| 135 | + |
| 136 | +Money Transfer example has three separate processes. One to host workflow code, |
| 137 | +another activity, and the third one to request transfers. |
| 138 | + |
| 139 | +Start workflow worker: |
| 140 | + |
| 141 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountTransferWorker |
116 | 142 |
|
117 | | -The produced exception trace is part of the sample, so don't get confused by it. |
| 143 | +Start activity worker: |
118 | 144 |
|
119 | | -### Notes for MacOSX Users |
120 | | -Due to issues with default hostname resolution (see https://stackoverflow.com/questions/33289695/inetaddress-getlocalhost-slow-to-run-30-seconds), MacOSX Users may see gRPC DEADLINE_EXCEEDED errors in normal operation. |
| 145 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountActivityWorker |
| 146 | + |
| 147 | +Execute once per requested transfer: |
121 | 148 |
|
122 | | -This can be solved by adding the following entries to your `/etc/hosts` file (where my-macbook is your hostname): |
| 149 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.TransferRequester |
123 | 150 |
|
124 | | -```conf |
125 | | -127.0.0.1 my-macbook |
126 | | -::1 my-macbook |
127 | | -``` |
| 151 | +### Money Batch |
| 152 | + |
| 153 | +[The sample](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/moneybatch) |
| 154 | +demonstrates a situation when a single deposit should be initiated for multiple withdrawals. |
| 155 | +For example, a seller might want to be paid once per fixed number of transactions. |
| 156 | +The sample can be easily extended to perform a payment based on more complex criteria like a specific time |
| 157 | +or accumulated amount. |
| 158 | + |
| 159 | +The sample also demonstrates *signal with start* way of starting workflows. If the workflow is already running, it |
| 160 | +just receives the signal. If it is not running, then it is started first, and then the signal is delivered to it. |
| 161 | +You can think about *signal with start* as a lazy way to create workflows when signaling them. |
| 162 | + |
| 163 | +Money Batch example has three separate processes. One to host workflow code, |
| 164 | +another activity, and the third one to request transfers. |
| 165 | + |
| 166 | +Start workflow worker: |
| 167 | + |
| 168 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.AccountTransferWorker |
| 169 | + |
| 170 | +Start activity worker: |
| 171 | + |
| 172 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.AccountActivityWorker |
| 173 | + |
| 174 | +Execute at least three times to request three transfers (example batch size): |
| 175 | + |
| 176 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.TransferRequester |
| 177 | + |
| 178 | +### Updatable Timer |
| 179 | + |
| 180 | +The [Updatable Timer](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/updatabletimer) sample |
| 181 | +demonstrates a helper class which relies on Workflow.await to implement a blocking sleep that can be updated at any moment. |
| 182 | + |
| 183 | +Money Batch example has three separate processes. One to host workflow code, |
| 184 | +another to start workflow execution, and the third one to send signals to request timer updates. |
| 185 | + |
| 186 | +Start workflow worker: |
| 187 | + |
| 188 | + ./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker |
| 189 | + |
| 190 | +Start workflow execution: |
| 191 | + |
| 192 | + ./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.DynamicSleepWorkflowStarter |
| 193 | + |
| 194 | +Extend timer duration: |
| 195 | + |
| 196 | + ./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.WakeUpTimeUpdater |
0 commit comments