|
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 | | -* [Temporal Java Client](https://github.com/temporalio/temporal-java-sdk) |
5 | | -* [Go Temporal Client](https://github.com/temporalio/temporal-go-sdk) |
| 5 | +* [Temporal Java SDK](https://github.com/temporalio/temporal-java-sdk) |
| 6 | +* [Temporal Go SDK](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 |
34 | 28 |
|
35 | | -## Import into IntelliJ |
| 29 | +### Build the Samples |
36 | 30 |
|
37 | | -In the IntelliJ user interface, navigate to **File**->**New**->**Project from Existing Sources**. |
| 31 | + ./gradlew build |
38 | 32 |
|
39 | | -Select the cloned directory. In the **Import Project page**, select **Import project from external model**, |
40 | | -choose **Gradle** and then click **Next**->**Finish**. |
| 33 | +### Import into IntelliJ |
41 | 34 |
|
42 | | -## Build the Samples |
| 35 | +It is possible to run the samples from the command line, but if you prefer the IntelliJ here are the import steps: |
43 | 36 |
|
44 | | - ./gradlew build |
| 37 | +* Navigate to **File**->**New**->**Project from Existing Sources**. |
| 38 | +* Select the cloned directory. |
| 39 | +* In the **Import Project page**, select **Import project from external model** |
| 40 | +* Choose **Gradle** and then click **Next** |
| 41 | +* Click **Finish**. |
45 | 42 |
|
46 | | -## Run Temporal Server |
| 43 | +### Run Temporal Server |
47 | 44 |
|
48 | | -Run Temporal Server using Docker Compose: |
| 45 | +Samples require Temporal service to run. We recommend a locally running version of Temporal Server |
| 46 | +managed through [Docker Compose](https://docs.docker.com/compose/gettingstarted/): |
49 | 47 |
|
50 | 48 | curl -L https://github.com/temporalio/temporal/releases/latest/download/docker.tar.gz | tar -xz --strip-components 1 docker/docker-compose.yml |
51 | 49 | docker-compose up |
52 | 50 |
|
53 | 51 | If this does not work, see the instructions for running Temporal Server at https://github.com/temporalio/temporal/blob/master/README.md. |
54 | 52 |
|
55 | | -## See Temporal UI (Not Available yet!) |
| 53 | +## See Temporal UI |
56 | 54 |
|
57 | 55 | The Temporal Server running in a docker container includes a Web UI. |
58 | 56 |
|
59 | 57 | Connect to [http://localhost:8088](http://localhost:8088). |
60 | 58 |
|
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 | 59 | Click on a *RUN ID* of a workflow to see more details about it. Try different view formats to get a different level |
66 | 60 | of details about the execution history. |
67 | 61 |
|
68 | | -## Install Temporal CLI |
| 62 | +## Install Temporal CLI (tctl) |
69 | 63 |
|
70 | | -[Command Line Interface Documentation](https://docs.temporal.io/docs/08_running_temporal/02_cli) |
| 64 | +[Command Line Interface Documentation](https://docs.temporal.io/docs/tctl) |
71 | 65 |
|
72 | | -## Run the samples |
| 66 | +## Samples |
73 | 67 |
|
74 | 68 | Each sample has specific requirements for running it. The following sections contain information about |
75 | 69 | how to run each of the samples after you've built them using the preceding instructions. |
76 | 70 |
|
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 |
| 71 | +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)! |
| 72 | + |
| 73 | +### HelloWorld |
| 74 | + |
| 75 | +Each Hello World sample demonstrates one feature of the SDK in a single file. Note that single file format is |
| 76 | +used for sample brevity and is not something we recommend for real applications. |
| 77 | + |
| 78 | + * **[HelloActivity](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloActivity.java)**: a single activity workflow |
| 79 | + * **[HelloActivityRetry](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloActivityRetry.java)**: how to retry an activity |
| 80 | + * **[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 |
| 81 | + * **[HelloAsyncActivityCompletion](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloAsyncActivityCompletion.java)**: an asynchronous activity implementation |
| 82 | + * **[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) |
| 83 | + * **[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 |
| 84 | + * **[HelloChild](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloChild.java)**: a child workflow |
| 85 | + * **[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 |
| 86 | + * **[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 |
| 87 | + * **[HelloException](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloException.java)**: exception propagation and wrapping |
| 88 | + * **[HelloPolymorphicActivity](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloPolymorphicActivity.java)**: activities that extend a common interface |
| 89 | + * **[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 |
| 90 | + * **[HelloSignal](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloSignal.java)**: sending and handling a signal |
| 91 | + * **[HelloSaga](https://github.com/temporalio/java-samples/blob/master/src/main/java/io/temporal/samples/hello/HelloSaga.java)**: SAGA pattern support |
| 92 | + * **[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 |
| 93 | + |
| 94 | + To run the hello world samples: |
| 95 | + |
| 96 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivity |
| 97 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivityRetry |
| 98 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsync |
| 99 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsyncActivityCompletion |
| 100 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsyncLambda |
| 101 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloCancellationScope |
| 102 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloChild |
| 103 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloCron |
| 104 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloException |
| 105 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPeriodic |
| 106 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPolymorphicActivity |
| 107 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloQuery |
| 108 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSaga |
| 109 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignal |
| 110 | + ./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSearchAttributes |
94 | 111 |
|
95 | 112 | ### File Processing |
96 | | - |
97 | | -This sample has two executables. Execute each command in a separate terminal window. The first command |
| 113 | +[FileProcessing](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/fileprocessing) |
| 114 | +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. |
| 115 | + |
| 116 | +The sample has two executables. Execute each command in a separate terminal window. The first command |
98 | 117 | 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. |
| 118 | +execute together, we recommend running more than one instance of this worker. |
100 | 119 |
|
101 | 120 | ./gradlew -q execute -PmainClass=io.temporal.samples.fileprocessing.FileProcessingWorker |
102 | 121 |
|
103 | 122 | The second command starts workflows. Each invocation starts a new workflow execution. |
104 | 123 |
|
105 | 124 | ./gradlew -q execute -PmainClass=io.temporal.samples.fileprocessing.FileProcessingStarter |
106 | 125 |
|
107 | | -### Trip Booking |
108 | | - |
109 | | -Temporal implementation of the [Camunda BPMN trip booking example](https://github.com/berndruecker/trip-booking-saga-java) |
| 126 | +### Booking SAGA |
110 | 127 |
|
111 | | -Demonstrates Temporal approach to SAGA. |
| 128 | +[Booking SAGA](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/bookingsaga) |
| 129 | +is a Temporal take on Camunda BPMN trip booking example. |
112 | 130 |
|
113 | 131 | To run: |
114 | 132 |
|
115 | 133 | ./gradlew -q execute -PmainClass=io.temporal.samples.bookingsaga.TripBookingSaga |
| 134 | + |
| 135 | +### Money Transfer |
| 136 | + |
| 137 | +Basic [Money Transfer](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/moneytransfer) example. |
| 138 | + |
| 139 | +Money Transfer example has three separate processes. One to host workflow code, |
| 140 | +another activity, and the third one to request transfers. |
| 141 | + |
| 142 | +Start workflow worker: |
| 143 | + |
| 144 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountTransferWorker |
116 | 145 |
|
117 | | -The produced exception trace is part of the sample, so don't get confused by it. |
| 146 | +Start activity worker: |
118 | 147 |
|
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. |
| 148 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountActivityWorker |
| 149 | + |
| 150 | +Execute once per requested transfer: |
121 | 151 |
|
122 | | -This can be solved by adding the following entries to your `/etc/hosts` file (where my-macbook is your hostname): |
| 152 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.TransferRequester |
123 | 153 |
|
124 | | -```conf |
125 | | -127.0.0.1 my-macbook |
126 | | -::1 my-macbook |
127 | | -``` |
| 154 | +### Money Batch |
| 155 | + |
| 156 | +[The sample](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/moneybatch) |
| 157 | +demonstrates a situation when a single deposit should be initiated for multiple withdrawals. |
| 158 | +For example, a seller might want to be paid once per fixed number of transactions. |
| 159 | +The sample can be easily extended to perform a payment based on more complex criteria like a specific time |
| 160 | +or accumulated amount. |
| 161 | + |
| 162 | +The sample also demonstrates *signal with start* way of starting workflows. If the workflow is already running, it |
| 163 | +just receives the signal. If it is not running, then it is started first, and then the signal is delivered to it. |
| 164 | +You can think about *signal with start* as a lazy way to create workflows when signaling them. |
| 165 | + |
| 166 | +Money Batch example has three separate processes. One to host workflow code, |
| 167 | +another activity, and the third one to request transfers. |
| 168 | + |
| 169 | +Start workflow worker: |
| 170 | + |
| 171 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.AccountTransferWorker |
| 172 | + |
| 173 | +Start activity worker: |
| 174 | + |
| 175 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.AccountActivityWorker |
| 176 | + |
| 177 | +Execute at least three times to request three transfers (example batch size): |
| 178 | + |
| 179 | + ./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.TransferRequester |
| 180 | + |
| 181 | +### Updatable Timer |
| 182 | + |
| 183 | +The [Updatable Timer](https://github.com/temporalio/java-samples/tree/master/src/main/java/io/temporal/samples/updatabletimer) sample |
| 184 | +demonstrates a helper class which relies on Workflow.await to implement a blocking sleep that can be updated at any moment. |
| 185 | + |
| 186 | +Money Batch example has three separate processes. One to host workflow code, |
| 187 | +another to start workflow execution, and the third one to send signals to request timer updates. |
| 188 | + |
| 189 | +Start workflow worker: |
| 190 | + |
| 191 | + ./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker |
| 192 | + |
| 193 | +Start workflow execution: |
| 194 | + |
| 195 | + ./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.DynamicSleepWorkflowStarter |
| 196 | + |
| 197 | +Extend timer duration: |
| 198 | + |
| 199 | + ./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.WakeUpTimeUpdater |
0 commit comments