Demos various aspects of Temporal using the Java SDK.
A Typescript SDK version of this example is also available.
The sample is configured by default to connect to a local Temporal Server running on localhost:7233.
To instead connect to Temporal Cloud, set the following environment variables, replacing them with your own Temporal Cloud credentials:
TEMPORAL_ADDRESS=testnamespace.sdvdw.tmprl.cloud:7233
TEMPORAL_NAMESPACE=testnamespace.sdvdw
TEMPORAL_CERT_PATH="/path/to/file.pem"
TEMPORAL_KEY_PATH="/path/to/file.key"
(optional) set a task queue name
export TEMPORAL_MONEYTRANSFER_TASKQUEUE="MoneyTransferJava"
Note: Use a Java 18 SDK.
Start a worker:
ENCRYPT_PAYLOADS=true ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.AccountTransferWorker --console=plain
Run the money transfer web UI:
ENCRYPT_PAYLOADS=true ./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.web.WebServer --console=plain
Then navigate to http://localhost:7070/
A dropdown menu simulates the following scenarios
- The transfer will run to completion
The transfer will in addition to running to completion, upsert a search attribute called Step. The Step search attribute defines what part of the workflow is being executed: withdraw or deposit. By upserting a search attribute we are able to search workflows by not only execution status, time, duration but also, based on business logic exposed by the search attribute.
In order to demonstrate this feature the search attribute Step
which is a Keyword
must be created in the Temporal namespace. This can be accomplished using the UI or CLI.
The transfer will pause and wait for approval. If the user doesn't approve the transfer within a set time, the workflow will fail.
Approve a transfer using Signals
# where TRANSFER-EZF-249 is the workflowId
./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.TransferApprover -Parg=TRANSFER-XXX-XXX
You can also do this through the temporal
cli:
temporal workflow signal \
--env prod \
--query 'WorkflowId="TRANSFER-XXX-XXX"' \
--name approveTransfer \
--reason 'approving transfer'
Approve a transfer using Updates
You can do this through the temporal
cli:
temporal workflow update \
--env prod \
--workflow-id TRANSFER-XXX-XXX \
--name approveTransferUpdate
The workflow's Update function has a validator. It will reject an Update if:
- The transfer isn't waiting for approval
- The transfer has already been approved
Comment out the RuntimeException in the workflow code (AccountTransferWorkflowImpl.java
) and restart the worker to fix the 'bug'.
Will introduce artifical delays in the withdraw
activity's API calls. This will cause activity retries. After 5 retries, the delay will be removed and the workflow will proceed.
Introduces an unrecoverable failure in the deposit
activity (invalid account). The workflow will fail after running compensation activities (undoWithdraw
).
Creates a Schedule that will run a set of workflows on a cadence.
Produces a schedule ID, which you can inspect in the Temporal UI's "Schedules" menu.
temporal workflow list --env prod -q 'ExecutionStatus="Failed" OR ExecutionStatus="Terminated"'
Remove the ENCRYPT_PAYLOADS
variable in each command to run without encryption.
You can decrypt these payloads in Temporal Cloud's UI/cli using the codec server: https://codec.tmprl-demo.cloud
(source). Ensure you switch on "Pass the user access token with your endpoint". Note: The codec server is only compatible with workflows running in Temporal Cloud.
See the Worker Auto Tuning guide for information on how to use Worker Auto-Tuning to optimize worker resource usage.
When step-debugging, ensure environment variable TEMPORAL_DEBUG=true
is set, to avoid deadlock detection.
Example command (run from root directory)
./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.RecentHistoryReplayer
Introduce a non-determinism error by adding Workflow.Sleep or re-arranging activity executions:
error=io.temporal.worker.NonDeterministicException:
Failure handling event 15 of type 'EVENT_TYPE_ACTIVITY_TASK_SCHEDULED' during replay.
No command scheduled that corresponds to event_id: 15
# Note: This replayer doesn't work with histories using ENCRYPT_PAYLOADS=true
Example command (run from root directory)
./gradlew -q execute -PmainClass=io.temporal.samples.moneytransfer.Replayer \
-Parg=../workflowHistories/non-deterministic.json # or happy-path.json
The organization of UI code is 'less than perfect'. It's a todo list item for the future to refactor it.
- The UI code is based on the SvelteKit framework.
- It lives in the Typescript version of the Money Transfer example under
./ui
. - A compiled version was built and copied to this Java example repository
- To modify and test the UI:
- Deploy the Typescript version of the Money Transfer example
- Modify the UI code in the Typescript version
- Run and test that version, it will build the UI
- If the UI works in the Typescript version, it will work in the Java one
- Deploy a new version of the UI into the Java example
- Remove the existing UI directory:
temporal-money-transfer-java/core/src/main/resources/svelte_ui/build
- Copy the UI from the Typescript example to the Java example:
- Remove the existing UI directory:
cp -r /path/to/temporal-money-transfer/server/build \
/path/to/temporal-money-transfer-java/core/src/main/resources/svelte_ui