ExecuteActivityAsync syntax in .NET
To spawn an Activity Execution in a .NET Workflow, use the ExecuteActivityAsync method with a lambda expression targeting the Activity method and Activity Options. Example: await Workflow.ExecuteActivityAsync((MyActivities a) => a.MyActivity(param), new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) }).
Get Activity Execution results
The Activity result is returned in the Task from the ExecuteActivityAsync call. The awaited result provides the return value from the Activity Execution.
Spawn Activity Execution in .NET
Activity Executions are spawned from within a Workflow Definition using the ExecuteActivityAsync method. The call generates a ScheduleActivityTask Command, which creates three Activity Task related Events in the Workflow Execution Event History: ActivityTaskScheduled, ActivityTaskStarted, and ActivityTaskClosed.
Heartbeat method in .NET activity
To Heartbeat an Activity Execution in .NET, use the Heartbeat() method on the ActivityExecutionContext.
Heartbeat with details in .NET
Heartbeats support detail data that persists on the server for retrieval during Activity retry. When an Activity calls Heartbeat with detail arguments, such as Heartbeat(123, 456), and then fails and is retried, the HeartbeatDetails property on ActivityInfo returns a collection containing those values on the next run.
ListActivitiesAsync for Standalone Activities in .NET
Use client.ListActivitiesAsync() to list Standalone Activity Executions that match a List Filter query. The result is an IAsyncEnumerable that yields ActivityExecution entries. This API returns only Standalone Activity Executions. Activities running inside Workflows are not included.
CountActivitiesAsync for Standalone Activities in .NET
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.
StartActivityAsync example in .NET
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}");
ListActivitiesAsync example in .NET
await foreach (var info in client.ListActivitiesAsync(
"TaskQueue = 'standalone-activity-sample'"))
{
Console.WriteLine(
$"ActivityID: {info.ActivityId}, Type: {info.ActivityType}, Status: {info.Status}");
}
ExecuteActivityAsync for Standalone Activities in .NET
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.
CountActivitiesAsync example in .NET
var resp = await client.CountActivitiesAsync(
"TaskQueue = 'standalone-activity-sample'");
Console.WriteLine($"Total activities: {resp.Count}");
GetResultAsync for Standalone Activity handles in .NET
Call await handle.GetResultAsync() on an activity handle to wait for the Activity to be executed and return the result. Calling client.ExecuteActivityAsync() is equivalent to calling client.StartActivityAsync() followed by await handle.GetResultAsync().
GetActivityHandle in .NET
Use client.GetActivityHandle() to create a handle to a previously started Standalone Activity. You can create a handle without a known result type or with a known result type. The handle can be used to wait for the result, describe, cancel, or terminate the Activity.
GetActivityHandle examples in .NET
// 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");
ExecuteActivityAsync example in .NET
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}");
ExecuteActivityAsync with string type name in .NET
var result = await client.ExecuteActivityAsync<string>(
"ComposeGreeting",
new object?[] { new ComposeGreetingInput("Hello", "World") },
new("standalone-activity-id", "standalone-activity-sample")
{
ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
});
StartActivityAsync for Standalone Activities in .NET
Use client.StartActivityAsync() to start a Standalone Activity and get a handle without waiting for the result. This durably enqueues the Standalone Activity but returns immediately with an activity handle.
Executing Activity with Summary metadata
```csharp
using Temporalio.Activities;
using Temporalio.Workflows;
[Workflow]
public class YourWorkflow
{
[WorkflowRun]
public async Task<string> RunAsync(string input)
{
var result = await Workflow.ExecuteActivityAsync(
(YourActivities act) => act.YourActivityAsync(input),
new ActivityOptions
{
StartToCloseTimeout = TimeSpan.FromSeconds(10),
Summary = "Processing user data"
});
return result;
}
}
```
This example demonstrates attaching a Summary to an Activity execution within a Workflow.
Activity Summary in ActivityOptions
When executing an Activity from within a Workflow using Workflow.ExecuteActivityAsync, you can attach a Summary metadata parameter in ActivityOptions. The Summary is a string limited to 200 bytes that displays on the Timeline and in Event History to provide context about the Activity execution.
ExecuteActivityAsync with activity options
Use Workflow.ExecuteActivityAsync to call an activity from a workflow. Pass a lambda expression where the instance is typed (or a static method reference). Provide activity options as the second parameter, such as StartToCloseTimeout set to TimeSpan.FromMinutes(5) for a 5-minute timeout.
Multiple Activity Executions from a Workflow
It is idiomatic to invoke multiple Activity Executions from within a Workflow. It is also idiomatic to either block on the results of the Activity Executions or continue on to execute additional logic, checking for the Activity Execution results at a later time using the Future's IsReady() method.
Example: Set ScheduleToCloseTimeout
activityOptions := workflow.ActivityOptions{
ScheduleToCloseTimeout: 10 * time.Second,
}
ctx = workflow.WithActivityOptions(ctx, activityOptions)
var yourActivityResult YourActivityResult
err = workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam).Get(ctx, &yourActivityResult)
if err != nil {
// ...
}
Example: Get Activity Execution result with Get()
func YourWorkflowDefinition(ctx workflow.Context, param YourWorkflowParam) (YourWorkflowResponse, error) {
// ...
future := workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam)
var yourActivityResult YourActivityResult
if err := future.Get(ctx, &yourActivityResult); err != nil {
// ...
}
// ...
}
Example: Check Activity result readiness before Get()
func YourWorkflowDefinition(ctx workflow.Context, param YourWorkflowParam) (YourWorkflowResponse, error) {
// ...
future := workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam)
// ...
if(future.IsReady()) {
var yourActivityResult YourActivityResult
if err := future.Get(ctx, &yourActivityResult); err != nil {
// ...
}
}
// ...
}
workflow.Future methods for Activity results
ExecuteActivity returns an instance of workflow.Future with two methods:
1. Get(ctx workflow.Context, valuePtr interface{}): Takes an instance of workflow.Context and a pointer parameter. The variable associated with the pointer is populated with the Activity Execution result. This call blocks until results are available. The type of the result parameter must match the type of the return value declared by the Activity function.
2. IsReady(): Returns true when the result of the Activity Execution is ready.
Example: Set RetryPolicy
retryPolicy := &temporal.RetryPolicy{
InitialInterval: time.Second,
BackoffCoefficient: 2.0,
MaximumInterval: time.Second * 100,
}
activityOptions := workflow.ActivityOptions{
RetryPolicy: retryPolicy,
}
ctx = workflow.WithActivityOptions(ctx, activityOptions)
var yourActivityResult YourActivityResult
err = workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam).Get(ctx, &yourActivityResult)
if err != nil {
// ...
}
Example: Set TaskQueueName
activityOptions := workflow.ActivityOptions{
TaskQueueName: "your-task-queue-name",
}
ctx = workflow.WithActivityOptions(ctx, activityOptions)
var yourActivityResult YourActivityResult
err = workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam).Get(ctx, &yourActivityResult)
if err != nil {
// ...
}
Example: Set ActivityID
activityOptions := workflow.ActivityOptions{
ActivityID: "your-activity-id",
}
ctx = workflow.WithActivityOptions(ctx, activityOptions)
var yourActivityResult YourActivityResult
err = workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam).Get(ctx, &yourActivityResult)
if err != nil {
// ...
}
Example: Execute Activity with options and get result
func YourWorkflowDefinition(ctx workflow.Context, param YourWorkflowParam) (*YourWorkflowResultObject, error) {
activityOptions := workflow.ActivityOptions{
StartToCloseTimeout: 10 * time.Second,
}
ctx = workflow.WithActivityOptions(ctx, activityOptions)
activityParam := YourActivityParam{
ActivityParamX: param.WorkflowParamX,
ActivityParamY: param.WorkflowParamY,
}
var a *YourActivityObject
var activityResult YourActivityResultObject
err := workflow.ExecuteActivity(ctx, a.YourActivityDefinition, activityParam).Get(ctx, &activityResult)
if err != nil {
return nil, err
}
}
ExecuteActivity API for spawning Activity Executions
To spawn an Activity Execution, call ExecuteActivity() inside a Workflow Definition. The API is available from the go.temporal.io/sdk/workflow package. ExecuteActivity() requires an instance of workflow.Context, the Activity function name (as a function object or string), and any variables to be passed to the Activity. Passing the function object allows the framework to validate parameters against the Activity Definition. ExecuteActivity returns a Future that can be used to get the Activity Execution result.
RetryPolicy option
RetryPolicy is an optional RetryPolicy field in ActivityOptions. Type: temporal.RetryPolicy. Default retry policy values: InitialInterval: 1 second, BackoffCoefficient: 2.0, MaximumInterval: 100 seconds, MaximumAttempts: 0 (Unlimited), NonRetryableErrorTypes: empty. Providing a Retry Policy overwrites individual field defaults.
OriginalTaskQueueName option
OriginalTaskQueueName is an optional string field in ActivityOptions. Used to specify the original Task Queue name for Activity routing.
HeartbeatTimeout option
HeartbeatTimeout is an optional time.Duration field in ActivityOptions. Sets the Heartbeat Timeout for the Activity Execution.
StartToCloseTimeout option
StartToCloseTimeout is a time.Duration field in ActivityOptions. This or ScheduleToCloseTimeout must be set. Default: Same as ScheduleToCloseTimeout. Sets the Start-To-Close Timeout for the Activity Execution.
ScheduleToStartTimeout option
ScheduleToStartTimeout is an optional time.Duration field in ActivityOptions. Default: ∞ (infinity - no limit). Sets the Schedule-To-Start Timeout for the Activity Execution.
TaskQueueName option
TaskQueueName is an optional string field in ActivityOptions. Default: Inherits the TaskQueue name from the Workflow. Use this to route an Activity Execution to a different Task Queue than the Workflow.
ActivityID option
ActivityID is an optional string field in ActivityOptions with no default value. It is used to assign a unique identifier to an Activity Execution.
WaitForCancellation option
WaitForCancellation is an optional bool field in ActivityOptions. Default: false. If true, the Activity Execution will finish executing even if there is a Cancellation request.
Go ActivityOptions fields reference
ActivityOptions from go.temporal.io/sdk/workflow supports the following fields:
| Field | Required | Type |
|-------|----------|------|
| ActivityID | No | string |
| TaskQueueName | No | string |
| ScheduleToCloseTimeout | Yes (or StartToCloseTimeout) | time.Duration |
| ScheduleToStartTimeout | No | time.Duration |
| StartToCloseTimeout | Yes (or ScheduleToCloseTimeout) | time.Duration |
| HeartbeatTimeout | No | time.Duration |
| WaitForCancellation | No | bool |
| OriginalTaskQueueName | No | string |
| RetryPolicy | No | RetryPolicy |
Apply options to workflow.Context using WithActivityOptions().
Required Activity Timeouts
Either a Schedule-To-Close Timeout or a Start-To-Close Timeout must be set in Activity Options. These are the only required timeout values. Timeouts are set in an instance of ActivityOptions from the go.temporal.io/sdk/workflow package, then applied using WithActivityOptions() API to the workflow.Context instance.
Execute standalone activity code example
package main
import (
"context"
"github.com/temporalio/samples-go/standalone-activity/helloworld"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/contrib/envconfig"
"log"
"time"
)
func main() {
c, err := client.Dial(envconfig.MustLoadDefaultClientOptions())
if err != nil {
log.Fatalln("Unable to create client", err)
}
defer c.Close()
activityOptions := client.StartActivityOptions{
ID: "standalone_activity_helloworld_ActivityID",
TaskQueue: "standalone-activity-helloworld",
ScheduleToCloseTimeout: 10 * time.Second,
}
handle, err := c.ExecuteActivity(context.Background(), activityOptions, helloworld.Activity, "Temporal")
if err != nil {
log.Fatalln("Unable to execute activity", err)
}
log.Println("Started standalone activity", "ActivityID", handle.GetID(), "RunID", handle.GetRunID())
var result string
err = handle.Get(context.Background(), &result)
if err != nil {
log.Fatalln("Unable get standalone activity result", err)
}
log.Println("Activity result:", result)
}
This example shows how to execute a standalone activity, wait for completion, and retrieve the result.
ExecuteActivity method for standalone activities
Use client.ExecuteActivity() to start a Standalone Activity Execution from application code. This returns an ActivityHandle that you can use to get the result, describe, cancel, or terminate the Activity. You can pass the Activity as either a function reference or a string Activity type name.
Temporal CLI for standalone activities
Standalone Activities can be executed using the Temporal CLI with the command: temporal activity execute --type Activity --activity-id <id> --task-queue <queue-name> --schedule-to-close-timeout <duration> --input <json-input>. The Temporal CLI can also be used to retrieve activity results with temporal activity result --activity-id <id>, list activities with temporal activity list, and count activities with temporal activity count.
ListActivities method and scope
Use client.ListActivities() to list Standalone Activity Executions that match a List Filter query. The result contains an iterator that yields ActivityExecutionInfo entries. These APIs return only Standalone Activity Executions; Activities running inside Workflows are not included.
ActivityHandle.Get() method
Use ActivityHandle.Get() to block until the Activity completes and retrieve its result. This is analogous to calling Get() on a WorkflowRun. If the Activity completed successfully, the result is deserialized into the provided pointer. If the Activity failed, the failure is returned as an error.
Standalone Activities with Temporal Cloud
The same code works against Temporal Cloud without code changes by using envconfig.MustLoadDefaultClientOptions(), which responds to environment variables and TOML configuration files. For mTLS connection, set TEMPORAL_ADDRESS, TEMPORAL_NAMESPACE, TEMPORAL_TLS_CLIENT_CERT_PATH, and TEMPORAL_TLS_CLIENT_KEY_PATH. For API key connection, set TEMPORAL_ADDRESS, TEMPORAL_NAMESPACE, and TEMPORAL_API_KEY.
GetActivityHandle for existing standalone activities
Use client.GetActivityHandle() to create a handle to a previously started Standalone Activity. This is analogous to client.GetWorkflow() for Workflow Executions. Both ActivityID and RunID are required.
Activity heartbeat from external source in Go
Activity Heartbeats can be recorded from an external source using the RecordActivityHeartbeat function. The temporalClient must be created once per process, and called with the taskToken (binary TaskToken field from ActivityInfo struct retrieved inside the Activity) and details (serializable payload with progress information).
Record heartbeat in Go activity
To Heartbeat in an Activity in Go, use the activity.RecordHeartbeat API with the activity context and details parameter. This sends the heartbeat ping and progress information to the Temporal Service.
Activity timeout example in Go
activityoptions := workflow.ActivityOptions{
ScheduleToCloseTimeout: 10 * time.Second,
}
ctx = workflow.WithActivityOptions(ctx, activityoptions)
var yourActivityResult YourActivityResult
err = workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam).Get(ctx, &yourActivityResult)
if err != nil {
// handle error
}
Setting activity timeouts in Go code
To set an Activity Timeout in Go, create an instance of ActivityOptions from the go.temporal.io/sdk/workflow package, set the desired timeout field (ScheduleToCloseTimeout, StartToCloseTimeout, or ScheduleToStartTimeout), and then use the WithActivityOptions() API to apply the options to the workflow.Context instance before calling ExecuteActivity().
Activity timeout types in Go
The Go SDK supports three activity timeouts through ActivityOptions: ScheduleToCloseTimeout (maximum duration for overall Activity Execution), StartToCloseTimeout (maximum time for a single Activity Task Execution), and ScheduleToStartTimeout (maximum time from when an Activity Task is scheduled to when a Worker starts it, non-retryable by design). An Activity Execution must have either the Start-To-Close or the Schedule-To-Close Timeout set.
Heartbeat timeout failure details
When an Activity Task Execution times out due to a missed Heartbeat, the last value of the details variable is returned to the calling Workflow in the details field of TimeoutError with TimeoutType set to Heartbeat.
Heartbeat timeout in Go
A Heartbeat Timeout works in conjunction with Activity Heartbeats. To set it, create an instance of ActivityOptions from the go.temporal.io/sdk/workflow package, set the HeartbeatTimeout field, and use the WithActivityOptions() API to apply the options to the workflow.Context instance.
RecordActivityHeartbeat external example in Go
temporalClient, err := client.Dial(client.Options{})
err := temporalClient.RecordActivityHeartbeat(ctx, taskToken, details)
Resume activity from heartbeat details example in Go
func SampleActivity(ctx context.Context, inputArg InputParams) error {
startIdx := inputArg.StartIndex
if activity.HasHeartbeatDetails(ctx) {
var finishedIndex int
if err := activity.GetHeartbeatDetails(ctx, &finishedIndex); err == nil {
startIdx = finishedIndex + 1
}
}
for i:=startIdx; i<inputArg.EndIdx; i++ {
// Code for processing item i goes here
activity.RecordHeartbeat(ctx, i)
}
}
Heartbeat timeout example in Go
activityoptions := workflow.ActivityOptions{
HeartbeatTimeout: 10 * time.Second,
}
ctx = workflow.WithActivityOptions(ctx, activityoptions)
var yourActivityResult YourActivityResult
err = workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam).Get(ctx, &yourActivityResult)
ActivityOptions StartToCloseTimeout in Go
The StartToCloseTimeout in workflow.ActivityOptions specifies the maximum duration an Activity can run before timing out. It is set as a time.Duration value, for example: time.Second * 10 for a 10-second timeout.
Activity Heartbeat example for Cloud Run safety
Example showing Activity Heartbeat usage for safe execution during Cloud Run scale-in:
```go
func MyActivity(ctx context.Context, input MyInput) (string, error) {
for i := range input.Items {
activity.RecordHeartbeat(ctx, i)
// ... process input.Items[i]
}
return "done", nil
}
```
WaitForCancellation Activity Option
The ActivityOptions struct includes a WaitForCancellation field. When set to true in activity options, the activity will wait for and respond to cancellation requests before completing execution.