Skip to content

Latest commit

 

History

History
383 lines (283 loc) · 8.88 KB

File metadata and controls

383 lines (283 loc) · 8.88 KB
id standalone-activities-interactive-demo
title Standalone Activities Interactive Demo
sidebar_label Standalone Activities (Interactive)
toc_max_heading_level 3
keywords
standalone activity
activity execution
execute activity
activity handle
quickstart
interactive demo
tags
Activities
Temporal Client
Temporal SDKs
description An interactive quickstart for Temporal Standalone Activities — run Activities directly from a Temporal Client without a Workflow.

:::tip SUPPORT, STABILITY, and DEPENDENCY INFO

Temporal SDK support for Standalone Activities is at Pre-release.

All APIs are experimental and may be subject to backwards-incompatible changes.

:::

Standalone Activities let you execute an Activity directly from a Temporal Client — no Workflow required. The Activity is durably enqueued on the Temporal Server, executed by a Worker, and its result is returned to the caller.

Use the interactive demo below to explore the API, experiment with failure scenarios, and see the generated SDK code and CLI command update in real time.

import { StandaloneActivityDemo } from '@site/src/components';


How it works

When you call client.ExecuteActivity() (or the equivalent in your SDK), the following happens:

  1. Connect — Your application connects to the Temporal Server.
  2. Schedule — The Server durably persists the Activity execution on the specified Task Queue.
  3. Poll — A Worker polling that Task Queue picks up the Activity Task.
  4. Execute — The Worker runs your Activity function with the provided arguments.
  5. Return — The result is stored by the Server and returned to the original caller via the ActivityHandle.

Because the Server durably persists the Activity, it survives Worker restarts and network interruptions. If the Activity fails, the Server automatically retries it according to the Retry Policy you configure.

Standalone vs Workflow Activities

Workflow Activity Standalone Activity
Orchestrated by A Workflow Definition Your application code
Started with workflow.ExecuteActivity() client.ExecuteActivity()
Retry policy Configured per ActivityOptions Configured per StartActivityOptions
Visibility Workflow Event History Activity Visibility (List/Count)
Use case Complex, multi-step orchestration Simple, independent jobs

The Activity function and Worker registration are identical for both — only the execution path differs.


Setup

1. Install the Temporal CLI

Download the Standalone Activity prerelease build of the Temporal CLI:

# macOS (Homebrew)
brew install temporal

# Or download directly from GitHub
# https://github.com/temporalio/cli/releases/tag/v1.6.2-standalone-activity

2. Start a local development server

temporal server start-dev

The server starts at localhost:7233 and the Web UI at http://localhost:8233. Standalone Activities appear under the Activities nav item in the Web UI.

3. Install the SDK

import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';

Requires Go SDK v1.41.0 or higher.

go get go.temporal.io/sdk@latest

Clone the samples repository to follow along:

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

Requires Python SDK v1.23.0 or higher.

uv add temporalio
# or: pip install temporalio

Clone the samples repository to follow along:

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

Requires .NET SDK v1.12.0 or higher.

dotnet add package Temporalio

Clone the samples repository to follow along:

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

4. Run the Worker

The Worker registers the Activity and polls the Task Queue. Start it in a dedicated terminal:

go run standalone-activity/helloworld/worker/main.go
uv run hello_standalone_activity/worker.py
dotnet run --project src/StandaloneActivity worker

5. Execute the Activity

In a separate terminal, run the starter:

go run standalone-activity/helloworld/starter/main.go
uv run hello_standalone_activity/execute_activity.py
dotnet run --project src/StandaloneActivity execute-activity

Or use the Temporal CLI directly:

temporal activity execute \
  --type Activity \
  --activity-id my-activity-id \
  --task-queue my-task-queue \
  --start-to-close-timeout 10s \
  --input '"World"'

Key API concepts

ExecuteActivity — start and wait

The primary call. Durably enqueues the Activity, waits for execution, and returns the result:

handle, err := c.ExecuteActivity(ctx, client.StartActivityOptions{
    ID:                  "my-activity-id",
    TaskQueue:           "my-task-queue",
    StartToCloseTimeout: 10 * time.Second,
}, helloworld.Activity, "World")

var result string
err = handle.Get(ctx, &result)
result = await client.execute_activity(
    compose_greeting,
    args=[ComposeGreetingInput("Hello", "World")],
    id="my-activity-id",
    task_queue="my-task-queue",
    start_to_close_timeout=timedelta(seconds=10),
)
var result = await client.ExecuteActivityAsync(
    () => MyActivities.ComposeGreetingAsync(
        new ComposeGreetingInput("Hello", "World")),
    new("my-activity-id", "my-task-queue")
    {
        StartToCloseTimeout = TimeSpan.FromSeconds(10),
    });

StartActivity — fire and forget

Enqueues the Activity without waiting for it to finish. Useful when you want to kick off long-running work and check back later:

handle, err := c.ExecuteActivity(ctx, options, helloworld.Activity, "World")
// handle.Get() can be called later
handle = await client.start_activity(
    compose_greeting,
    args=[ComposeGreetingInput("Hello", "World")],
    id="my-activity-id",
    task_queue="my-task-queue",
    start_to_close_timeout=timedelta(seconds=10),
)
# Later:
result = await handle.result()
var handle = await client.StartActivityAsync(
    () => MyActivities.ComposeGreetingAsync(
        new ComposeGreetingInput("Hello", "World")),
    new("my-activity-id", "my-task-queue")
    {
        StartToCloseTimeout = TimeSpan.FromSeconds(10),
    });
// Later:
var result = await handle.GetResultAsync();

List and Count Activities

// List
resp, err := c.ListActivities(ctx, client.ListActivitiesOptions{
    Query: "TaskQueue = 'my-task-queue'",
})
for info, err := range resp.Results { ... }

// Count
resp, err := c.CountActivities(ctx, client.CountActivitiesOptions{
    Query: "TaskQueue = 'my-task-queue'",
})
log.Println("Total:", resp.Count)
# List
async for info in client.list_activities(
    query="TaskQueue = 'my-task-queue'"
):
    print(info.activity_id, info.status)

# Count
resp = await client.count_activities(
    query="TaskQueue = 'my-task-queue'"
)
print("Total:", resp.count)
// List
await foreach (var info in client.ListActivitiesAsync(
    "TaskQueue = 'my-task-queue'"))
{
    Console.WriteLine($"{info.ActivityId}: {info.Status}");
}

// Count
var resp = await client.CountActivitiesAsync(
    "TaskQueue = 'my-task-queue'");
Console.WriteLine($"Total: {resp.Count}");

The Query parameter uses the same List Filter syntax as Workflow Visibility.


Next steps

For complete API reference and advanced usage, see the SDK-specific guides: