Creating Workflows

The workflow is the implementation of the coordination logic. The Cadence programming framework (aka client library) allows you to write the workflow coordination logic as simple procedural code that uses standard Go data modeling. The client library takes care of the communication between the worker service and the Cadence service, and ensures state persistence between events even in case of worker failures. Furthermore, any particular execution is not tied to a particular worker machine. Different steps of the coordination logic can end up executing on different worker instances, with the framework ensuring that the necessary state is recreated on the worker executing the step.

However, in order to facilitate this operational model, both the Cadence programming framework and the managed service impose some requirements and restrictions on the implementation of the coordination logic. The details of these requirements and restrictions are described in the Implementation section below.


The sample code below shows a simple implementation of a workflow that executes one activity. The workflow also passes the sole parameter it receives as part of its initialization as a parameter to the activity.

package sample

import (


func init() {

func SimpleWorkflow(ctx workflow.Context, value string) error {
    ao := workflow.ActivityOptions{
        TaskList:               "sampleTaskList",
        ScheduleToCloseTimeout: time.Second * 60,
        ScheduleToStartTimeout: time.Second * 60,
        StartToCloseTimeout:    time.Second * 60,
        HeartbeatTimeout:       time.Second * 10,
        WaitForCancellation:    false,
    ctx = workflow.WithActivityOptions(ctx, ao)

    future := workflow.ExecuteActivity(ctx, SimpleActivity, value)
    var result string
    if err := future.Get(ctx, &result); err != nil {
        return err
    workflow.GetLogger(ctx).Info("Done", zap.String("result", result))
    return nil


In the Cadence programing model, a workflow is implemented with a function. The function declaration specifies the parameters the workflow accepts as well as any values it might return.

    func SimpleWorkflow(ctx workflow.Context, value string) error

Let’s deconstruct the declaration above:


In order to support the synchronous and sequential programming model for the workflow implementation, there are certain restrictions and requirements on how the workflow implementation must behave in order to guarantee correctness. The requirements are that:

A straightforward way to think about these requirements is that the workflow code is as follows:

Now that we have laid the ground rules, we can take a look at some of the special functions and types used for writing Cadence workflows and how to implement some common patterns.

Special Cadence client library functions and types

The Cadence client library provides a number of functions and types as alternatives to some native Go functions and types. Usage of these replacement functions/types is necessary in order to ensure that the workflow code execution is deterministic and repeatable within an execution context.

Coroutine related constructs:

Time related functions:

Failing a workflow

To mark a workflow as failed, all that needs to happen is for the workflow function to return an error via the err return value.


For some client code to be able to invoke a workflow type, the worker process needs to be aware of all the implementations it has access to. A workflow is registered with the following call:


This call essentially creates an in-memory mapping inside the worker process between the fully qualified function name and the implementation. It is safe to call this registration method from an init() function. If the worker receives tasks for a workflow type it does not know, it will fail that task. However, the failure of the task will not cause the entire workflow to fail.