Standalone Activities Feature Guide
Standalone Activities are Activities that run independently, without being orchestrated by a
Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone
Activity directly from a Temporal Client using ActivityClient.
The way you write the Activity and register it with a Worker is identical to Workflow Activities. The only difference is that you execute a Standalone Activity directly from your Temporal Client.
New to Standalone Activities? Start with the Standalone Activities Quickstart.
This page covers the following:
- Start a Standalone Activity without waiting for the result
- Get a handle to an existing Standalone Activity
- Wait for the result of a Standalone Activity
- List Standalone Activities
- Count Standalone Activities
- Run Standalone Activities with Temporal Cloud
This documentation uses source code from the standaloneactivities sample.
Start a Standalone Activity without waiting for the result
Starting a Standalone Activity means sending a request to the Temporal Server to durably enqueue your Activity job, without waiting for it to be executed by your Worker.
Use
ActivityClient.start()
to start a Standalone Activity and get a handle without waiting for the result:
ActivityHandle<String> handle =
client.start(
GreetingActivities.class,
GreetingActivities::composeGreeting,
options,
"Hello",
"World");
System.out.println("Started activity ID: " + ACTIVITY_ID);
// Wait for the result later
String result = handle.getResult();
System.out.println("Activity result: " + result);
With the Temporal Server and Worker running, open a new terminal in the samples-java directory and
run:
./gradlew -q execute -PmainClass=io.temporal.samples.standaloneactivities.StartActivity
Or use the Temporal CLI:
./temporal activity start \
--type ComposeGreeting \
--activity-id standalone-activity-id \
--task-queue standalone-activity-task-queue \
--start-to-close-timeout 10s \
--input '"Hello"' \
--input '"World"'
Get a handle to an existing Standalone Activity
Use client.getHandle() to create a typed handle to a previously started Standalone Activity:
ActivityHandle<String> handle =
client.getHandle("standalone-activity-id", null, String.class);
Pass null as the run ID to target the latest run of the given activity ID. You can then use the
handle to wait for the result, describe, cancel, or terminate the Activity.
Wait for the result of a Standalone Activity
Under the hood, calling client.execute() is the same as calling client.start() to durably
enqueue the Standalone Activity, and then calling handle.getResult() to block until the Activity
completes and return the result:
String result = handle.getResult();
To wait asynchronously without blocking the calling thread, use handle.getResultAsync(), which
returns a CompletableFuture<R>:
CompletableFuture<String> future = handle.getResultAsync();
Or use the Temporal CLI to wait for a result by Activity ID:
./temporal activity result --activity-id standalone-activity-id
List Standalone Activities
Use
client.listExecutions()
to list Standalone Activity Executions that match a List Filter query. The result is
a Stream<ActivityExecutionMetadata> that fetches pages from the server on demand as the stream is
consumed.
These APIs return only Standalone Activity Executions. Activities running inside Workflows are not included.
client
.listExecutions("TaskQueue = '" + TASK_QUEUE + "'")
.forEach(
info ->
System.out.printf(
"ActivityID: %s, Type: %s, Status: %s%n",
info.getActivityId(), info.getActivityType(), info.getStatus()));
Run it:
./gradlew -q execute -PmainClass=io.temporal.samples.standaloneactivities.ListActivities
Or use the Temporal CLI:
./temporal activity list
The query parameter accepts the same List Filter syntax used for Workflow
Visibility. For example, ActivityType = 'composeGreeting' AND Status = 'Running'.
Count Standalone Activities
Use
client.countExecutions()
to count Standalone Activity Executions that match a List Filter query. This returns
the total count of executions (running, completed, failed, etc.) — not the number of queued tasks.
It works the same way as counting Workflow Executions.
ActivityExecutionCount resp = client.countExecutions("TaskQueue = '" + TASK_QUEUE + "'");
System.out.println("Total activities: " + resp.getCount());
resp.getGroups()
.forEach(
group ->
System.out.println("Group " + group.getGroupValues() + ": " + group.getCount()));
Run it:
./gradlew -q execute -PmainClass=io.temporal.samples.standaloneactivities.CountActivities
Or use the Temporal CLI:
./temporal activity count
Run Standalone Activities with Temporal Cloud
The Worker and Client code in the Standalone Activities Quickstart
use ClientConfigProfile.load(), so the same code works against Temporal Cloud — configure the
connection via environment variables or a TOML profile. No code changes are needed.
For a step-by-step guide on connecting to Temporal Cloud, including Namespace creation, certificate generation, and authentication setup in the Cloud UI, see Connect to Temporal Cloud.
Connect with mTLS
Set these environment variables with values from your Temporal Cloud Namespace settings:
export TEMPORAL_ADDRESS=<your-namespace>.<your-account-id>.tmprl.cloud:7233
export TEMPORAL_NAMESPACE=<your-namespace>.<your-account-id>
export TEMPORAL_TLS_CLIENT_CERT_PATH='path/to/your/client.pem'
export TEMPORAL_TLS_CLIENT_KEY_PATH='path/to/your/client.key'
Connect with an API key
Set these environment variables with values from your Temporal Cloud API key settings:
export TEMPORAL_ADDRESS=<your-namespace>.<your-account-id>.tmprl.cloud:7233
export TEMPORAL_NAMESPACE=<your-namespace>.<your-account-id>
export TEMPORAL_API_KEY=<your-api-key>
Then run the Worker and starter code as shown in the Standalone Activities Quickstart.