Skip to main content

Activity basics - Go SDK

How to develop an Activity Definition in Go

In the Temporal Go SDK programming model, an Activity Definition is an exportable function or a struct method. Below is an example of both a basic Activity Definition and of an Activity defined as a Struct method. An Activity struct can have more than one method, with each method acting as a separate Activity Type. Activities written as struct methods can use shared struct variables, such as:

  • an application level DB pool
  • client connection to another service
  • reusable utilities
  • any other expensive resources that you only want to initialize once per process

Because this is such a common need, the rest of this guide shows Activities written as struct methods.

note

While it is possible to register struct methods as Workflows, this is strongly discouraged. In some cases, struct methods as Workflows may cause non-deterministic errors. We recommend only using struct methods for Activities.

View the source code

in the context of the rest of the application code.

package yourapp

import (
"context"

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

// YourSimpleActivityDefinition is a basic Activity Definition.
func YourSimpleActivityDefinition(ctx context.Context) error {
return nil
}

// YourActivityObject is the struct that maintains shared state across Activities.
// If the Worker crashes this Activity object loses its state.
type YourActivityObject struct {
Message *string
Number *int
}

// YourActivityDefinition is your custom Activity Definition.
// An Activity Definition is an exportable function.
func (a *YourActivityObject) YourActivityDefinition(ctx context.Context, param YourActivityParam) (*YourActivityResultObject, error) {
// ...
}

How to develop Activity Parameters

There is no explicit limit to the total number of parameters that an Activity Definition may support. However, there is a limit to the total size of the data that ends up encoded into a gRPC message Payload.

A single argument is limited to a maximum size of 2 MB. And the total size of a gRPC message, which includes all the arguments, is limited to a maximum of 4 MB.

Also, keep in mind that all Payload data is recorded in the Workflow Execution Event History and large Event Histories can affect Worker performance. This is because the entire Event History could be transferred to a Worker Process with a Workflow Task.

Some SDKs require that you pass context objects, others do not. When it comes to your application data—that is, data that is serialized and encoded into a Payload—we recommend that you use a single object as an argument that wraps the application data passed to Activities. This is so that you can change what data is passed to the Activity without breaking a function or method signature.

The first parameter of an Activity Definition is context.Context. This parameter is optional for an Activity Definition, though it is recommended, especially if the Activity is expected to use other Go SDK APIs.

An Activity Definition can support as many other custom parameters as needed. However, all parameters must be serializable (parameters can't be channels, functions, variadic, or unsafe pointers), and it is recommended to pass a single struct that can be updated later.

View the source code

in the context of the rest of the application code.

// YourActivityParam is the struct passed to your Activity.
// Use a struct so that your function signature remains compatible if fields change.
type YourActivityParam struct {
ActivityParamX string
ActivityParamY int
}
// ...
func (a *YourActivityObject) YourActivityDefinition(ctx context.Context, param YourActivityParam) (*YourActivityResultObject, error) {
// ...
}

How to define Activity return values

All data returned from an Activity must be serializable.

Activity return values are subject to payload size limits in Temporal. The default payload size limit is 2MB, and there is a hard limit of 4MB for any gRPC message size in the Event History transaction (see Cloud limits here). Keep in mind that all return values are recorded in a Workflow Execution Event History.

A Go-based Activity Definition can return either just an error or a customValue, error combination (same as a Workflow Definition). You may wish to use a struct type to hold all custom values, just keep in mind they must all be serializable.

View the source code

in the context of the rest of the application code.

// YourActivityResultObject is the struct returned from your Activity.
// Use a struct so that you can return multiple values of different types.
// Additionally, your function signature remains compatible if the fields change.
type YourActivityResultObject struct {
ResultFieldX string
ResultFieldY int
}
// ...
func (a *YourActivityObject) YourActivityDefinition(ctx context.Context, param YourActivityParam) (*YourActivityResultObject, error) {
// ...
result := &YourActivityResultObject{
ResultFieldX: "Success",
ResultFieldY: 1,
}
// Return the results back to the Workflow Execution.
// The results persist within the Event History of the Workflow Execution.
return result, nil
}

How to customize Activity Type in Go

To customize the Activity Type, set the Name parameter with RegisterOptions when registering your Activity with a Worker.

View the source code

in the context of the rest of the application code.

func main() {
// ...
yourWorker := worker.New(temporalClient, "your-custom-task-queue-name", worker.Options{})
// ...
// Use RegisterOptions to change the name of the Activity Type for example.
registerAOptions := activity.RegisterOptions{
Name: "JustAnotherActivity",
}
yourWorker.RegisterActivityWithOptions(yourapp.YourSimpleActivityDefinition, registerAOptions)
// Run the Worker
err = yourWorker.Run(worker.InterruptCh())
// ...
}
// ...