Skip to main content

How to develop a Workflow in Go

Use the Dial() API available in the go.temporal.io/sdk/client package to create a new Client

func YourWorkflowDefinition(ctx workflow.Context) error {
// ...
return nil
}

In Go, by default, the Workflow Type name is the same as the function name.

Parameters

The first parameter of a Go-based Workflow Definition must be of the workflow.Context type, as it is used by the Temporal Go SDK to pass around Workflow Execution context, and virtually all the Go SDK APIs that are callable from the Workflow require it. It is acquired from the go.temporal.io/sdk/workflow package.

import (
"go.temporal.io/sdk/workflow"
)

func YourWorkflowDefinition(ctx workflow.Context, param string) error {
// ...
}

The workflow.Context entity operates similarly to the standard context.Context entity provided by Go. The only difference between workflow.Context and context.Context is that the Done() function, provided by workflow.Context, returns workflow.Channel instead of the standard Go chan.

The second parameter, string, is a custom parameter that is passed to the Workflow when it is invoked. A Workflow Definition may support multiple custom parameters, or none. These parameters can be regular type variables or safe pointers. However, the best practice is to pass a single parameter that is of a struct type, so there can be some backward compatibility if new parameters are added.

type YourWorkflowParam struct {
WorkflowParamFieldOne string
WorkflowParamFieldTwo int
}

func YourWorkflowDefinition(ctx workflow.Context, param YourWorkflowParam) error {
// ...
}

All Workflow Definition parameters must be serializable, regardless of whether pointers or regular type values are used. Parameters can’t be channels, functions, variadic, or unsafe pointers.

Return values

A Go-based Workflow Definition can return either just an error or a customValue, error combination. Again, the best practice here is to use a struct type to hold all custom values.

type YourWorkflowResponse struct{
WorkflowResultFieldOne string
WorkflowResultFieldTwo int
}

func YourWorkflowDefinition(ctx workflow.Context, param YourWorkflowParam) (YourWorkflowResponse, error) {
// ...
if err != nil {
return "", err
}
responseVar := YourWorkflowResponse {
FieldOne: "super",
FieldTwo: 1,
}
return responseVar, nil
}

A Workflow Definition written in Go can return both a custom value and an error. However, it's not possible to receive both a custom value and an error in the calling process, as is normal in Go. The caller will receive either one or the other. Returning a non-nil error from a Workflow indicates that an error was encountered during its execution and the Workflow Execution should be terminated, and any custom return values will be ignored by the system.

Logic requirements

In Go, Workflow Definition code cannot directly do the following:

  • Iterate over maps using range, because with range the order of the map's iteration is randomized. Instead you can collect the keys of the map, sort them, and then iterate over the sorted keys to access the map. This technique provides deterministic results. You can also use a Side Effect or an Activity to process the map instead.
  • Call an external API, conduct a file I/O operation, talk to another service, etc. (Use an Activity for these.)

The Temporal Go SDK has APIs to handle equivalent Go constructs:

  • workflow.Now() This is a replacement for time.Now().
  • workflow.Sleep() This is a replacement for time.Sleep().
  • workflow.GetLogger() This ensures that the provided logger does not duplicate logs during a replay.
  • workflow.Go() This is a replacement for the go statement.
  • workflow.Channel This is a replacement for the native chan type. Temporal provides support for both buffered and unbuffered channels.
  • workflow.Selector This is a replacement for the select statement. Learn more on the Go SDK Selectors page
  • workflow.Context This is a replacement for context.Context. Learn more on the Go SDK Context Propagation page.