Skip to main content

Quickstart

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.

info

This documentation uses source code from the StandaloneActivity sample project.

Get started with Standalone Activities

Prerequisites:

  • .NET 8.0+

  • Temporal .NET SDK (v1.12.0 or higher). See the .NET Quickstart for install instructions.

  • Temporal CLI v1.7.0 or higher. Install with Homebrew, or see the Temporal CLI install guide for other platforms. Verify the installation with temporal --version.

Start the Temporal development server with temporal server start-dev.

This command automatically starts the Temporal development server with the Web UI, and creates the default Namespace. It uses an in-memory database, so do not use it for real use cases.

The Temporal Server will now be available for client connections on localhost:7233, and the Temporal Web UI will now be accessible at http://localhost:8233.

brew install temporal
temporal --version
temporal server start-dev

Clone the sample

Clone the samples-dotnet repository to follow along:

git clone https://github.com/temporalio/samples-dotnet.git
cd samples-dotnet

The sample project is structured as follows:

src/StandaloneActivity/
├── MyActivities.cs
├── Program.cs
├── README.md
└── TemporalioSamples.StandaloneActivity.csproj

Define your Activity

An Activity in the Temporal .NET SDK is a method decorated with the [Activity] attribute. The way you write a Standalone Activity is identical to how you write an Activity orchestrated by a Workflow. In fact, the same Activity can be executed both as a Standalone Activity and as a Workflow Activity.

src/StandaloneActivity/MyActivities.cs

MyActivities.cs
namespace TemporalioSamples.StandaloneActivity;

using Temporalio.Activities;

public static class MyActivities
{
[Activity]
public static Task<string> ComposeGreetingAsync(ComposeGreetingInput input) =>
Task.FromResult($"{input.Greeting}, {input.Name}!");
}

public record ComposeGreetingInput(string Greeting, string Name);

Run a Worker with the Activity registered

Running a Worker for Standalone Activities is the same as running a Worker for Workflow Activities — you create a Worker, register the Activity, and run the Worker. The Worker doesn't need to know whether the Activity will be invoked from a Workflow or as a Standalone Activity. See How to develop a Worker for more details on Worker setup and configuration options.

src/StandaloneActivity/Program.cs

Open a new terminal, navigate to the samples-dotnet directory, and run the Worker. Leave this terminal running - the Worker needs to stay up to process activities.

Program.cs
using Microsoft.Extensions.Logging;
using Temporalio.Client;
using Temporalio.Common.EnvConfig;
using Temporalio.Worker;
using TemporalioSamples.StandaloneActivity;

var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
connectOptions.TargetHost ??= "localhost:7233";
connectOptions.LoggerFactory = LoggerFactory.Create(builder =>
builder.
AddSimpleConsole(options => options.TimestampFormat = "[HH:mm:ss] ").
SetMinimumLevel(LogLevel.Information));
var client = await TemporalClient.ConnectAsync(connectOptions);

const string taskQueue = "standalone-activity-sample";

using var tokenSource = new CancellationTokenSource();
Console.CancelKeyPress += (_, eventArgs) =>
{
tokenSource.Cancel();
eventArgs.Cancel = true;
};

using var worker = new TemporalWorker(
client,
new TemporalWorkerOptions(taskQueue).
AddActivity(MyActivities.ComposeGreetingAsync));

await worker.ExecuteAsync(tokenSource.Token);
dotnet run --project src/StandaloneActivity worker

Execute a Standalone Activity

Use client.ExecuteActivityAsync() to execute a Standalone Activity and wait for the result. Call this from your application code, not from inside a Workflow Definition. This durably enqueues your Standalone Activity in the Temporal Server, waits for it to be executed on your Worker, and then returns the result.

src/StandaloneActivity/Program.cs

You can pass the Activity as either a lambda expression or a string Activity type name.

StartActivityOptions requires Id, TaskQueue, and at least one of ScheduleToCloseTimeout or StartToCloseTimeout. See StartActivityOptions in the API reference for the full set of options.

To run it:

  1. Make sure the Temporal Server is running (from the Get Started step above).
  2. Make sure the Worker is running (from the Run a Worker step above).
  3. Open a new terminal, navigate to the samples-dotnet directory, and run dotnet run --project src/StandaloneActivity execute-activity.

Or use the Temporal CLI.

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 result = await client.ExecuteActivityAsync(
() => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")),
new("standalone-activity-id", "standalone-activity-sample")
{
ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
});
Console.WriteLine($"Activity result: {result}");
// Using a lambda expression (type-safe)
var result = await client.ExecuteActivityAsync(
() => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")),
new("standalone-activity-id", "standalone-activity-sample")
{
ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
});

// Using a string type name
var result = await client.ExecuteActivityAsync<string>(
"ComposeGreeting",
new object?[] { new ComposeGreetingInput("Hello", "World") },
new("standalone-activity-id", "standalone-activity-sample")
{
ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
});
dotnet run --project src/StandaloneActivity execute-activity
temporal activity execute \
--type ComposeGreeting \
--activity-id standalone-activity-id \
--task-queue standalone-activity-sample \
--schedule-to-close-timeout 10s \
--input '{"Greeting": "Hello", "Name": "World"}'

Run with Temporal Cloud

All code samples on this page use ClientEnvConfig.LoadClientConnectOptions() to configure the Temporal Client connection. It responds to environment variables and TOML configuration files, so the same code works against a local dev server and Temporal Cloud without changes. See Run Standalone Activities with Temporal Cloud in the Feature Guide for mTLS and API key setup.

Next steps