Skip to content

Commit 1c1b6d8

Browse files
skill-temporal-developer-updater[bot]skill-sync[bot]donald-pinckney
authored
Implement planned topic: 0037-standalone-activities-go (#241)
* Finalize draft for 0037-standalone-activities-go * Update Standalone Activities documentation for Go SDK Edits throughout Go standalone activities --------- Co-authored-by: skill-sync[bot] <skill-sync[bot]@users.noreply.github.com> Co-authored-by: Donald Pinckney <donald.pinckney@temporal.io>
1 parent 5f32b62 commit 1c1b6d8

10 files changed

Lines changed: 200 additions & 9 deletions

File tree

references/core/standalone-activities.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
# Standalone Activities (Concepts)
55

6-
This document provides core conceptual explanations of Standalone Activities in Temporal. For language-specific implementation details, see `references/{your_language}/standalone-activities.md` for the language you are working in (Python, TypeScript, Java, .NET).
6+
This document provides core conceptual explanations of Standalone Activities in Temporal. For language-specific implementation details, see `references/{your_language}/standalone-activities.md` for the language you are working in (Python, TypeScript, Java, .NET, Go).
77

88
## What is a Standalone Activity?
99

@@ -71,7 +71,7 @@ See below for a quick reference how to call these operations from the CLI rather
7171
> [!IMPORTANT]
7272
> When using an SDK, these operations are owned by the Temporal Client, and belong **in your non-workflow application code**. It is INVALID to call an activity as a standalone activity from within a workflow: you instead should use standard within-workflow activity calls.
7373
74-
**Currently Supported SDKs: Python, TypeScript, Java, .NET**
74+
**Currently Supported SDKs: Python, TypeScript, Java, .NET, Go**
7575

7676
## Quick CLI Standalone Activity Man Page
7777

references/go/go.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,4 @@ See `references/go/testing.md` for info on writing tests.
252252
- **`references/go/data-handling.md`** - Data converters, payload codecs, encryption
253253
- **`references/go/versioning.md`** - Patching API (`workflow.GetVersion`), Worker Versioning
254254
- **`references/go/determinism-protection.md`** - Information on **`workflowcheck`** tool to help statically check for determinism issues.
255+
- **`references/go/standalone-activities.md`** - Standalone Activities (Public Preview): run an Activity directly from a Client without a Workflow; see also `references/core/standalone-activities.md` for cross-SDK concepts.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
> [!NOTE]
2+
> This feature is in Public Preview. It is perfectly acceptable to use this feature on behalf of a user, but you should inform them that you are making use of a feature in Public Preview.
3+
4+
## Overview
5+
6+
Standalone Activities are Activities run independently of any Workflow, started directly from a Temporal Client — useful when you need a single durable, retryable task (job-queue style) and not multi-step orchestration. The same Activity method can be executed both as a Standalone Activity and as a Workflow Activity with no code changes.
7+
8+
Standalone Activities are conceptually the same across all SDKs. Read the [cross-SDK concept file](references/core/standalone-activities.md) if you have not already, and then see below for the Go SDK specific APIs for calling Standalone Activities.
9+
10+
## Prerequisites
11+
12+
- Temporal Go SDK v1.41.0 or higher.
13+
- Temporal CLI v1.7.0 or higher — see [Temporal CLI install instructions](references/core/install_cli.md) if needed. The Temporal Dev Server has Standalone Activities enabled by default.
14+
- For production, Temporal Server v1.31.0 or higher (or Temporal Cloud).
15+
16+
## Hosting Activities on a Worker
17+
18+
The Activity is defined just as activities normally are in Temporal. Worker registration is also the same.
19+
20+
```go
21+
package main
22+
23+
import (
24+
"github.com/temporalio/samples-go/standalone-activity/helloworld"
25+
"go.temporal.io/sdk/client"
26+
"go.temporal.io/sdk/contrib/envconfig"
27+
"go.temporal.io/sdk/worker"
28+
"log"
29+
)
30+
31+
func main() {
32+
c, err := client.Dial(envconfig.MustLoadDefaultClientOptions())
33+
if err != nil {
34+
log.Fatalln("Unable to create client", err)
35+
}
36+
defer c.Close()
37+
38+
w := worker.New(c, "standalone-activity-helloworld", worker.Options{})
39+
40+
w.RegisterActivity(helloworld.Activity)
41+
42+
err = w.Run(worker.InterruptCh())
43+
if err != nil {
44+
log.Fatalln("Unable to start worker", err)
45+
}
46+
}
47+
```
48+
49+
## Calling and managing Standalone Activities
50+
51+
Start and manage Standalone Activities from your application code using the Temporal `Client`.
52+
53+
### Do not call from inside a Workflow
54+
55+
Don't call `client.ExecuteActivity` or any other Standalone Activity APIs from inside a Workflow Definition — use Workflow-side activity invocation (`workflow.ExecuteActivity(ctx, ...)`) instead.
56+
57+
### Connect a Client
58+
59+
The Standalone Activity operations are methods on a connected `Client`. The examples below assume this client `c`.
60+
61+
```go
62+
import (
63+
"go.temporal.io/sdk/client"
64+
"go.temporal.io/sdk/contrib/envconfig"
65+
"context"
66+
)
67+
68+
c, err := client.Dial(envconfig.MustLoadDefaultClientOptions())
69+
if err != nil {
70+
log.Fatalln("Unable to create client", err)
71+
}
72+
defer c.Close()
73+
```
74+
75+
### Execute a Standalone Activity
76+
77+
Use `client.ExecuteActivity(...)` to durably enqueue the Activity. It then returns an `ActivityHandle` immediately — it does not wait for completion. After that, call `handle.Get(ctx, &out)` to wait for the result. There is no separate `Start` function in the Go SDK; `ExecuteActivity` is the only entry point.
78+
79+
`client.StartActivityOptions` requires `ID`, `TaskQueue`, and at least one of `ScheduleToCloseTimeout` or `StartToCloseTimeout`.
80+
81+
#### With type checking
82+
83+
Use when activity definitions are available in this language. Pass the activity function reference.
84+
85+
Pass the Activity as a function reference:
86+
87+
```go
88+
activityOptions := client.StartActivityOptions{
89+
ID: "send-welcome-email:user-42",
90+
TaskQueue: "standalone-activity-helloworld",
91+
ScheduleToCloseTimeout: 10 * time.Second,
92+
}
93+
94+
handle, err := c.ExecuteActivity(context.Background(), activityOptions, helloworld.Activity, "Temporal")
95+
if err != nil {
96+
log.Fatalln("Unable to execute activity", err)
97+
}
98+
99+
log.Println("Started", "ActivityID", handle.GetID(), "RunID", handle.GetRunID())
100+
101+
var result string
102+
err := handle.Get(context.Background(), &result)
103+
if err != nil {
104+
log.Fatalln("Activity failed", err)
105+
}
106+
log.Println("Activity result:", result)
107+
```
108+
109+
#### Without type checking
110+
111+
Use when activity definitions are unavailable in this language (i.e. you can't import them). Pass the activity type name as a string.
112+
113+
```go
114+
activityOptions := client.StartActivityOptions{
115+
ID: "send-welcome-email:user-42",
116+
TaskQueue: "standalone-activity-helloworld",
117+
ScheduleToCloseTimeout: 10 * time.Second,
118+
}
119+
120+
handle, err := c.ExecuteActivity(context.Background(), activityOptions, "Activity", "Temporal")
121+
if err != nil {
122+
log.Fatalln("Unable to execute activity", err)
123+
}
124+
125+
log.Println("Started", "ActivityID", handle.GetID(), "RunID", handle.GetRunID())
126+
127+
var result string
128+
err := handle.Get(context.Background(), &result)
129+
if err != nil {
130+
log.Fatalln("Activity failed", err)
131+
}
132+
log.Println("Activity result:", result)
133+
```
134+
135+
### Get a handle to an existing Activity execution
136+
137+
Use `client.GetActivityHandle()` to attach a handle to a previously started Standalone Activity. Both `ActivityID` and `RunID` are required.
138+
139+
```go
140+
handle := c.GetActivityHandle(client.GetActivityHandleOptions{
141+
ActivityID: "send-welcome-email:user-42",
142+
RunID: "the-run-id",
143+
})
144+
```
145+
146+
### Wait for the result of a handle
147+
148+
Call `handle.Get(ctx, &out)` to block until the Activity completes and deserialize its result into the provided pointer. If the Activity failed, the failure is returned as an error.
149+
150+
```go
151+
var result string
152+
err := handle.Get(context.Background(), &result)
153+
if err != nil {
154+
log.Fatalln("Activity failed", err)
155+
}
156+
log.Println("Activity result:", result)
157+
```
158+
159+
Calling `ExecuteActivity` and then `handle.Get(ctx, &out)` is the Go equivalent of the synchronous "Execute and wait" pattern that other SDKs offer as a single call.
160+
161+
### List Standalone Activities
162+
163+
```go
164+
resp, err := c.ListActivities(context.Background(), client.ListActivitiesOptions{
165+
Query: "TaskQueue = 'standalone-activity-helloworld'",
166+
})
167+
if err != nil {
168+
log.Fatalln("Unable to list activities", err)
169+
}
170+
171+
for info, err := range resp.Results { // a range-over-func iterator that yields `(ActivityExecutionInfo, error)` pairs.
172+
if err != nil {
173+
log.Fatalln("Error iterating activities", err)
174+
}
175+
log.Printf("ActivityID: %s, Type: %s, Status: %v\n",
176+
info.ActivityID, info.ActivityType, info.Status)
177+
}
178+
```
179+
180+
Only Standalone Activity Executions are returned; Activities running inside Workflows are not included.
181+
182+
### Count Standalone Activities
183+
184+
Use `client.CountActivities()` to count matching executions; this takes the **exact same arguments as `ListActivities`**.
185+
186+
```go
187+
resp, err := c.CountActivities(context.Background(), client.CountActivitiesOptions{
188+
Query: "TaskQueue = 'standalone-activity-helloworld'",
189+
})
190+
if err != nil {
191+
log.Fatalln("Unable to count activities", err)
192+
}
193+
194+
log.Println("Total activities:", resp.Count)
195+
```

references/python/advanced-features.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ client = await Client.connect(
134134

135135
- The only field is `resolution_interval_millis: int = 30000` — how often to re-resolve DNS, in milliseconds.
136136
- `DnsLoadBalancingConfig.default` is a pre-built instance with the default 30-second interval.
137-
- `dns_load_balancing_config` defaults to 30 seconds if you don't pass anything explicitly.
137+
- `dns_load_balancing_config` defaults to 30 seconds if you don't pass anything explicitly.
138138
- Pass `dns_load_balancing_config=None` to disable DNS load balancing entirely.
139139

140140
### Mutual exclusion with HTTP CONNECT proxy

references/python/integrations/google-adk.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ The integration is built on the Python SDK [Plugin system](https://docs.temporal
99
> [!NOTE]
1010
> This feature is in Public Preview. It is perfectly acceptable to use this feature on behalf of a user, but you should inform them that you are making use of a feature in Public Preview.
1111
12-
1312
For general Temporal AI/LLM patterns (retries, rate limits, multi-agent orchestration) see `references/core/ai-patterns.md` and `references/python/ai-patterns.md`.
1413

1514
## Prerequisites

references/python/integrations/langgraph.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,4 @@ For LangSmith tracing of LangGraph nodes and Temporal Activities together, use t
214214

215215
- `references/python/ai-patterns.md` — Python AI/LLM patterns (Pydantic data converter, LLM Activity design, retry/error classification).
216216
- `references/core/ai-patterns.md` — language-agnostic AI/LLM patterns.
217-
- `references/python/integrations/langsmith.md` - Companion LangSmith plugin.
217+
- `references/python/integrations/langsmith.md` - Companion LangSmith plugin.

references/python/integrations/langsmith.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ The plugin makes `@traceable` replay-safe in the Workflow sandbox. You do not ne
100100
- The plugin injects metadata using `workflow.now()` for timestamps and `workflow.random()` for UUIDs instead of `datetime.now()` and `uuid4()`.
101101
- LangSmith HTTP calls run on a background thread pool that does not interfere with deterministic Workflow execution.
102102

103-
104103
## Context propagation
105104

106105
Trace context flows automatically across Client → Workflow → Activity → Child Workflow → Nexus via Temporal headers. Do not pass context manually.

references/python/integrations/openai-agents-sdk.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ Note that the initial run context comes from the `context=...` argument you pass
164164

165165
In addition, since a `@function_tool` runs in the workflow, they can also call Temporal activities or other durable primitives themselves.
166166

167-
168167
**Don't put I/O, system clock, or sources of randomness inside a `@function_tool` body.** Make it an `@activity.defn` and wrap with `activity_as_tool` instead.
169168

170169
### Picking between the two

references/python/workflow-streams.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ Use it for modest fan-out progress streaming: AI-agent runs, order pipelines, mu
1111

1212
Only available in the Python SDK today; cross-language is on the roadmap.
1313

14-
1514
## When to use / not to use
1615

1716
- Use it for: updating a UI as an AI agent works; surfacing status from a payment or order pipeline; reporting intermediate results from a data job.

references/ruby/gotchas.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ require_relative 'activities/my_activity'
5959

6060
Transient network errors should be retried. Authentication errors should not be. See `references/ruby/error-handling.md` to understand how to classify errors with `non_retryable: true` and `non_retryable_error_types`.
6161

62-
6362
## Heartbeating
6463

6564
### Forgetting to Heartbeat Long Activities

0 commit comments

Comments
 (0)