Skip to main content

Standalone Activities Feature Guide

View Markdown

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.

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.

tip

New to Standalone Activities? Start with the Standalone Activities Quickstart.

This page covers the following:

info

This documentation uses source code from the StandaloneActivity sample project.

Start a Standalone Activity without waiting for the result

Use client.StartActivityAsync() to start a Standalone Activity and get a handle without waiting for the result:

src/StandaloneActivity/Program.cs

using Temporalio.Client;
using Temporalio.Common.EnvConfig;
using TemporalioSamples.StandaloneActivity;

var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
connectOptions.TargetHost ??= "localhost:7233";
var client = await TemporalClient.ConnectAsync(connectOptions);

var handle = await client.StartActivityAsync(
() => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")),
new("standalone-activity-id", "standalone-activity-sample")
{
ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
});
Console.WriteLine($"Started activity: {handle.Id}");

// Wait for the result later
var result = await handle.GetResultAsync();
Console.WriteLine($"Activity result: {result}");

With the Temporal Server and Worker running, open a new terminal in the samples-dotnet directory and run:

dotnet run --project src/StandaloneActivity start-activity

Or use the Temporal CLI:

temporal activity start \
--type ComposeGreeting \
--activity-id standalone-activity-id \
--task-queue standalone-activity-sample \
--schedule-to-close-timeout 10s \
--input '{"Greeting": "Hello", "Name": "World"}'

Get a handle to an existing Standalone Activity

Use client.GetActivityHandle() to create a handle to a previously started Standalone Activity:

// Without a known result type
var handle = client.GetActivityHandle("my-activity-id", runId: "the-run-id");

// With a known result type
var typedHandle = client.GetActivityHandle<string>("my-activity-id", runId: "the-run-id");

You can 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.ExecuteActivityAsync() is the same as calling client.StartActivityAsync() to durably enqueue the Standalone Activity, and then calling await handle.GetResultAsync() to wait for the Activity to be executed and return the result:

var result = await handle.GetResultAsync();

Or use the Temporal CLI to wait for a result by Activity ID:

temporal activity result --activity-id my-standalone-activity-id

List Standalone Activities

Use client.ListActivitiesAsync() to list Standalone Activity Executions that match a List Filter query. The result is an IAsyncEnumerable that yields ActivityExecution entries.

These APIs return only Standalone Activity Executions. Activities running inside Workflows are not included.

src/StandaloneActivity/Program.cs

using Temporalio.Client;
using Temporalio.Common.EnvConfig;

var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
connectOptions.TargetHost ??= "localhost:7233";
var client = await TemporalClient.ConnectAsync(connectOptions);

await foreach (var info in client.ListActivitiesAsync(
"TaskQueue = 'standalone-activity-sample'"))
{
Console.WriteLine(
$"ActivityID: {info.ActivityId}, Type: {info.ActivityType}, Status: {info.Status}");
}

Run it:

dotnet run --project src/StandaloneActivity list-activities

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.CountActivitiesAsync() 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.

src/StandaloneActivity/Program.cs

using Temporalio.Client;
using Temporalio.Common.EnvConfig;

var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
connectOptions.TargetHost ??= "localhost:7233";
var client = await TemporalClient.ConnectAsync(connectOptions);

var resp = await client.CountActivitiesAsync(
"TaskQueue = 'standalone-activity-sample'");
Console.WriteLine($"Total activities: {resp.Count}");

Run it:

dotnet run --project src/StandaloneActivity count-activities

Or use the Temporal CLI:

temporal activity count

Run Standalone Activities with Temporal Cloud

The code samples on this page use ClientEnvConfig.LoadClientConnectOptions(), so the same code works against Temporal Cloud - just 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.