diff --git a/docs/05-go-client/15-workflow-versioning.md b/docs/05-go-client/15-workflow-versioning.md index 1cb48cd60..50eca2881 100644 --- a/docs/05-go-client/15-workflow-versioning.md +++ b/docs/05-go-client/15-workflow-versioning.md @@ -135,6 +135,72 @@ but you want to ensure new :workflow:workflows: are running on new logic, you ca new `WorkflowType`, and change your start path (calls to `StartWorkflow()`) to start the new :workflow: type. +## Safe Deployment of Versioned Workflows + +When deploying workflow changes in production environments, you may want to separate the versioning +of the workflow code from the activation of new logic to ensure ability to roll back changes safely. +The `ExecuteWithVersion` and `ExecuteWithMinVersion` options provides this capability by allowing you +to control which version is returned when `GetVersion()` is executed for the first time. + +### Step 1: Deploy with Compatibility + +Initially, your workflow has the following code: + +```go +err = workflow.ExecuteActivity(ctx, FooActivity).Get(ctx, nil) +``` + +To safely roll out changes that replace `FooActivity` with `BarActivity`, you need both versions +of your workflow code to be compatible with each other. Use `GetVersion` with the `ExecuteWithMinVersion` option: + +```go +v := workflow.GetVersion(ctx, "fooToBarChange", workflow.DefaultVersion, 1, workflow.ExecuteWithMinVersion()) +// equivalent to +// v := workflow.GetVersion(ctx, "fooToBarChange", workflow.DefaultVersion, 1, workflow.ExecuteWithVersion(workflow.DefaultVersion)) +if v == workflow.DefaultVersion { + err = workflow.ExecuteActivity(ctx, FooActivity).Get(ctx, nil) +} else { + err = workflow.ExecuteActivity(ctx, BarActivity).Get(ctx, nil) +} +``` + +At this step: +- The previous version of the code supports only `DefaultVersion` +- The new version of the code supports both `DefaultVersion` and `1` +- The new version of the code is not yet activated, so workflows started on the new code will still execute the `FooActivity` (previous version) +- This makes it possible to safely roll back your changes if needed, as the previous code supports `DefaultVersion` only + +### Step 2: Activate New Logic + +When the previous version of the code is no longer running, you can activate the new code by removing the `ExecuteWithMinVersion` option: + +```go +v := workflow.GetVersion(ctx, "fooToBarChange", workflow.DefaultVersion, 1) +if v == workflow.DefaultVersion { + err = workflow.ExecuteActivity(ctx, FooActivity).Get(ctx, nil) +} else { + err = workflow.ExecuteActivity(ctx, BarActivity).Get(ctx, nil) +} +``` + +At this step: +- Both versions of the code support both `DefaultVersion` and `1` +- The new version of the code is activated, so workflows started on the new code will execute the `BarActivity` (new version) +- This still allows safe rollback because both versions of the code support both `DefaultVersion` and `1` + +### Step 3: Clean Up Old Code + +When there are no running workflows using `DefaultVersion`, you can remove the corresponding branch: + +```go +workflow.GetVersion(ctx, "fooToBarChange", 1, 1) +err = workflow.ExecuteActivity(ctx, BarActivity).Get(ctx, nil) +``` + +`ExecuteWithMinVersion` and `ExecuteWithVersion` options are particularly useful when you want to ensure that +your changes can be safely rolled back if needed, as both versions of the workflow code remain compatible with +each other throughout the deployment process. + ## Sanity checking The Cadence client SDK performs a sanity check to help prevent obvious incompatible changes.