Skip to content
8 changes: 8 additions & 0 deletions docs/develop/go/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ Complete Activities asynchronously.

- [How to asynchronously complete an Activity](/develop/go/asynchronous-activity-completion)

## [Standalone Activities](/develop/go/standalone-activities)

Execute Activities independently without a Workflow using the Temporal Client.

- [How to execute a Standalone Activity](/develop/go/standalone-activities#execute-activity)
- [How to get the result of a Standalone Activity](/develop/go/standalone-activities#get-activity-result)
- [How to get a handle to an existing Standalone Activity](/develop/go/standalone-activities#get-activity-handle)

## [Versioning](/develop/go/versioning)

Change Workflow Definitions without causing non-deterministic behavior in running Workflows.
Expand Down
313 changes: 313 additions & 0 deletions docs/develop/go/standalone-activities.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
---
id: standalone-activities
title: Standalone Activities - Go SDK
sidebar_label: Standalone Activities
toc_max_heading_level: 4
keywords:
- standalone activity
- activity execution
- execute activity
- activity handle
- list activities
- count activities
- go sdk
tags:
- Activities
- Temporal Client
- Go SDK
- Temporal SDKs
description: Execute Activities independently without a Workflow using the Temporal Go SDK.
---

:::tip SUPPORT, STABILITY, and DEPENDENCY INFO

Temporal TypeScript SDK support for Standalone Activities is at
[Pre-release](/evaluate/development-production-features/release-stages#pre-release).

:::

Standalone Activities are Activity Executions that run independently, without being orchestrated by a Workflow. Instead
of starting an Activity from within a Workflow Definition using `workflow.ExecuteActivity()`, you start a Standalone
Activity directly from a Temporal Client using `client.ExecuteActivity()`.

The Activity definition and Worker registration are identical to regular Activities, and only the execution path differs.

This page covers the following:

- [Run the Temporal Development Server with Standalone Activities enabled](#run-the-temporal-standalone-activity-development-server)
- [Run a worker with the activity registered](#run-worker)
- [Execute a Standalone Activity](#execute-activity)
- [Get the result of a Standalone Activity](#get-activity-result)
- [Get a handle to an existing Standalone Activity](#get-activity-handle)
- [List Standalone Activities](#list-activities)
- [Count Standalone Activities](#count-activities)

:::note

This documentation uses source code derived from the
[Go sample](https://github.com/temporalio/samples-go/tree/main/standalone-activity/helloworld).

:::

## Run the Temporal Development Server with Standalone Activities enabled {#run-the-temporal-standalone-activity-development-server}

Prerequisites:

- [Install the latest Temporal CLI](https://docs.temporal.io/develop/go/core-application#run-a-development-server)
(TO_BE_ANNOUNCED or higher recommended)
- [Install the latest Temporal Go SDK](https://docs.temporal.io/develop/go/core-application#install-a-temporal-sdk)
(v1.40.0 or higher recommended)

The first step in running a Standalone Activity involves starting a Temporal server.

```
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 Web UI should now be accessible at [http://localhost:8233](http://localhost:8233), and the Temporal Server
should now be available for client connections on `localhost:7233`.

## Run a worker with the activity registered {#run-worker}

Running a Worker for Standalone Activities is the same as running a Worker for Workflow-driven Activities — you create a
Worker, register the Activity, and call `Run()`. 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 in Go](/develop/go/core-application#develop-worker) for more details on Worker setup and
configuration options.

<div className="copycode-notice-container">
<a href="https://github.com/temporalio/samples-go/blob/main/standalone-activity/helloworld/worker/main.go">
View the source code
</a>{' '}
in the context of the rest of the application code.
</div>

```go
package main

import (
"context"
"go.temporal.io/sdk/activity"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/worker"
"log"
)

func MyActivity(ctx context.Context, name string) (string, error) {
logger := activity.GetLogger(ctx)
logger.Info("MyActivity", "name", name)
return "Hello " + name + "!", nil
}

func main() {
c, err := client.Dial(client.Options{})
if err != nil {
log.Fatalln("Unable to create client", err)
}
defer c.Close()

w := worker.New(c, "my-task-queue", worker.Options{})

w.RegisterActivity(MyActivity)

err = w.Run(worker.InterruptCh())
if err != nil {
log.Fatalln("Unable to start worker", err)
}
}

```

## Execute a Standalone Activity {#execute-activity}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally this quick start should allow users to cut/paste commands and have it working on their local machine with the least amount of work possible

so before this would add:

  • note saying everything is based on an SDK sample (with link), so they can clone it
  • commands (they can cut/paste) to clone, get dev server initialized, and the sample activity worker running, so it's ready to for a client to execute a Standalone Activity
  • then after this code walkthrough, would provide a command (they can cut/paste) to execute the standalone activity


Use [`client.ExecuteActivity()`](https://pkg.go.dev/go.temporal.io/sdk/client#Client) to start a Standalone Activity
Execution. This is called from application code (for example, a starter program), not from inside a Workflow Definition.

`ExecuteActivity` returns an [`ActivityHandle`](https://pkg.go.dev/go.temporal.io/sdk/client#ActivityHandle) that you
can use to get the result, describe, cancel, or terminate the Activity.

<div className="copycode-notice-container">
<a href="https://github.com/temporalio/samples-go/blob/main/standalone-activity/helloworld/starter/main.go">
View the source code
</a>{' '}
in the context of the rest of the application code.
</div>

```go
import (
"context"
"go.temporal.io/sdk/activity"
"log"
"time"

"go.temporal.io/sdk/client"
)

func MyActivity(ctx context.Context, name string) (string, error) {
logger := activity.GetLogger(ctx)
logger.Info("MyActivity", "name", name)
return "Hello " + name + "!", nil
}

func main() {
c, err := client.Dial(client.Options{})
if err != nil {
log.Fatalln("Unable to create client", err)
}
defer c.Close()

activityOptions := client.StartActivityOptions{
ID: "my-standalone-activity-id",
TaskQueue: "my-task-queue",
ScheduleToCloseTimeout: 10 * time.Second,
}

handle, err := c.ExecuteActivity(
context.Background(), activityOptions, MyActivity, "Temporal",
)
if err != nil {
log.Fatalln("Unable to execute standalone activity", err)
}

log.Println("Started standalone activity",
"ActivityID", handle.GetID(),
"RunID", handle.GetRunID(),
)
}
```

You can pass the Activity as either a function reference or a string Activity type name:

```go
handle, err := c.ExecuteActivity(ctx, options, MyActivity, "arg1")

// Using a string type name
handle, err := c.ExecuteActivity(ctx, options, "MyActivity", "arg1")
```

`client.StartActivityOptions` requires `ID`, `TaskQueue`, and at least one of `ScheduleToCloseTimeout` or
`StartToCloseTimeout`. See [`StartActivityOptions`](https://pkg.go.dev/go.temporal.io/sdk/client#StartActivityOptions)
in the API reference for the full set of options.

## Get the result of a Standalone Activity {#get-activity-result}

Use `ActivityHandle.Get()` to block until the Activity completes and retrieve its result. This is analogous to calling
`Get()` on a `WorkflowRun`.

```go
var result string
err = handle.Get(context.Background(), &result)
if err != nil {
log.Fatalln("Activity failed", err)
}
log.Println("Activity result:", result)
```

If the Activity completed successfully, the result is deserialized into the provided pointer. If the Activity failed,
the failure is returned as an error.

## Get a handle to an existing Standalone Activity {#get-activity-handle}

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.

```go
handle := c.GetActivityHandle(client.GetActivityHandleOptions{
ActivityID: "my-standalone-activity-id",
RunID: "the-run-id",
})

// Use the handle to get the result, describe, cancel, or terminate
var result string
err := handle.Get(context.Background(), &result)
if err != nil {
log.Fatalln("Unable to get activity result", err)
}
```

## List Standalone Activities {#list-activities}

Use [`client.ListActivities()`](https://pkg.go.dev/go.temporal.io/sdk/client#Client) to list Standalone Activity
Executions that match a [List Filter](/list-filter) query. The result contains an iterator that yields
[`ActivityExecutionInfo`](https://pkg.go.dev/go.temporal.io/sdk/client#ActivityExecutionInfo) entries.

```go
package main

import (
"context"
"fmt"
"log"

"go.temporal.io/sdk/client"
)

func main() {
c, err := client.Dial(client.Options{})
if err != nil {
log.Fatalln("Unable to create client", err)
}
defer c.Close()

resp, err := c.ListActivities(context.Background(), client.ListActivitiesOptions{
Query: "TaskQueue = 'my-task-queue'",
})
if err != nil {
log.Fatalln("Unable to list activities", err)
}

for info, err := range resp.Results {
if err != nil {
log.Fatalln("Error iterating activities", err)
}
fmt.Printf("ActivityID: %s, Type: %s, Status: %v\n",
info.ActivityID, info.ActivityType, info.Status)
}
}
```

The `Query` field accepts the same [List Filter](/list-filter) syntax used for Workflow Visibility. For example,
`"ActivityType = 'MyActivity' AND Status = 'Running'"`.

## Count Standalone Activities {#count-activities}

Use [`client.CountActivities()`](https://pkg.go.dev/go.temporal.io/sdk/client#Client) to count Standalone Activity
Executions that match a [List Filter](/list-filter) query.

```go
package main

import (
"context"
"fmt"
"log"

"go.temporal.io/sdk/client"
)

func main() {
c, err := client.Dial(client.Options{})
if err != nil {
log.Fatalln("Unable to create client", err)
}
defer c.Close()

resp, err := c.CountActivities(context.Background(), client.CountActivitiesOptions{
Query: "TaskQueue = 'my-task-queue'",
})
if err != nil {
log.Fatalln("Unable to count activities", err)
}

fmt.Println("Total activities:", resp.Count)

for _, group := range resp.Groups {
fmt.Printf("Group %v: %d\n", group.GroupValues, group.Count)
}
}
```
1 change: 1 addition & 0 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ module.exports = {
'develop/go/message-passing',
'develop/go/cancellation',
'develop/go/asynchronous-activity-completion',
'develop/go/standalone-activities',
'develop/go/versioning',
'develop/go/observability',
'develop/go/benign-exceptions',
Expand Down
Loading