These samples demonstrate various capabilities of Java Temporal client and server. You can learn more about Temporal at:
Due to issues with default hostname resolution
(see this StackOverflow question for more details),
macOS Users may see gRPC DEADLINE_EXCEEDED
errors when running the samples or any other gRPC related code.
To solve the problem add the following entries to your /etc/hosts
file (where my-macbook is your hostname):
127.0.0.1 my-macbook
::1 my-macbook
Run the following commands:
git clone https://github.com/temporalio/samples-java
cd samples-java
./gradlew build
It is possible to run the samples from the command line, but if you prefer the IntelliJ here are the import steps:
- Navigate to File->New->Project from Existing Sources.
- Select the cloned directory.
- In the Import Project page, select Import project from external model
- Choose Gradle and then click Next
- Click Finish.
Samples require Temporal service to run. We recommend a locally running version of Temporal Server managed through Docker Compose:
curl -L https://github.com/temporalio/temporal/releases/latest/download/docker.tar.gz | tar -xz --strip-components 1 docker/docker-compose.yml
docker-compose up
If this does not work, see the instructions for running Temporal Server at https://github.com/temporalio/temporal/blob/master/README.md.
The Temporal Server running in a docker container includes a Web UI.
Connect to http://localhost:8088.
Click on a RUN ID of a workflow to see more details about it. Try different view formats to get a different level of details about the execution history.
Command Line Interface Documentation
Each sample has specific requirements for running it. The following sections contain information about how to run each of the samples after you've built them using the preceding instructions.
Don't forget to check unit tests found under src/test/java!
Each Hello World sample demonstrates one feature of the SDK in a single file. Note that single file format is used for sample brevity and is not something we recommend for real applications.
- HelloActivity: a single activity workflow
- HelloActivityRetry: how to retry an activity
- HelloAsync: how to call activities asynchronously and wait for them using Promises
- HelloAsyncActivityCompletion: an asynchronous activity implementation
- HelloAsyncLambda: how to run part of a workflow asynchronously in a separate task (thread)
- HelloCancellationScope: how to explicitly cancel parts of a workflow
- HelloChild: a child workflow
- HelloCron: a workflow that is executed according to a cron schedule
- HelloPeriodic: a workflow that executes some logic periodically
- HelloException: exception propagation and wrapping
- HelloPolymorphicActivity: activities that extend a common interface
- HelloQuery: demonstrates how to query a state of a single workflow
- HelloSignal: sending and handling a signal
- HelloSaga: SAGA pattern support
- HelloSearchAttributes: Custom search attributes that can be used to find workflows using predicates
To run the hello world samples:
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivity
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloActivityRetry
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsync
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsyncActivityCompletion
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloAsyncLambda
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloCancellationScope
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloChild
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloCron
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloException
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPeriodic
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloPolymorphicActivity
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloQuery
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSaga
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignal
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSearchAttributes
FileProcessing 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.
The sample has two executables. Execute each command in a separate terminal window. The first command runs the worker that hosts the workflow and activities implementation. To demonstrate that activities execute together, we recommend running more than one instance of this worker.
./gradlew -q execute -PmainClass=io.temporal.samples.fileprocessing.FileProcessingWorker
The second command starts workflows. Each invocation starts a new workflow execution.
./gradlew -q execute -PmainClass=io.temporal.samples.fileprocessing.FileProcessingStarter
Booking SAGA is a Temporal take on Camunda BPMN trip booking example.
To run:
./gradlew -q execute -PmainClass=io.temporal.samples.bookingsaga.TripBookingSaga
Basic Money Transfer example.
Money Transfer example has three separate processes. One to host workflow code, another activity, and the third one to request transfers.
Start workflow worker:
./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountTransferWorker
Start activity worker:
./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountActivityWorker
Execute once per requested transfer:
./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.TransferRequester
The sample demonstrates a situation when a single deposit should be initiated for multiple withdrawals. For example, a seller might want to be paid once per fixed number of transactions. The sample can be easily extended to perform a payment based on more complex criteria like a specific time or accumulated amount.
The sample also demonstrates signal with start way of starting workflows. If the workflow is already running, it just receives the signal. If it is not running, then it is started first, and then the signal is delivered to it. You can think about signal with start as a lazy way to create workflows when signaling them.
Money Batch example has three separate processes. One to host workflow code, another activity, and the third one to request transfers.
Start workflow worker:
./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.AccountTransferWorker
Start activity worker:
./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.AccountActivityWorker
Execute at least three times to request three transfers (example batch size):
./gradlew -q execute -PmainClass=io.temporal.samples.moneybatch.TransferRequester
The Updatable Timer sample demonstrates a helper class which relies on Workflow.await to implement a blocking sleep that can be updated at any moment.
Money Batch example has three separate processes. One to host workflow code, another to start workflow execution, and the third one to send signals to request timer updates.
Start workflow worker:
./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.DynamicSleepWorkflowWorker
Start workflow execution:
./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.DynamicSleepWorkflowStarter
Extend timer duration:
./gradlew -q execute -PmainClass=io.temporal.samples.updatabletimer.WakeUpTimeUpdater