diff --git a/README.md b/README.md index 9d99f3b33..f49f14795 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,9 @@ These samples demonstrate some common control flow patterns using Temporal's Go - [**Worker-specific Task Queues**](./worker-specific-task-queues): Use a unique task queue per Worker to have certain Activities only run on that specific Worker. For instance for a file processing Workflow, where one Activity downloads a file and subsequent Activities need to operate on that file. (If multiple Workers were on the same queue, subsequent Activities may get run on different machines that don't have the downloaded file.) - [**Nexus**](./nexus): Demonstrates how to use the Nexus APIs to facilitate cross namespace calls. + - [**Nexus Cancelation**](./nexus-cancelation): Demonstrates how to cancel a Nexus operation from a caller workflow. + - [**Nexus Context Propagation**](./nexus-context-propagation): Demonstrates how to propagate context through client calls, workflows, and Nexus headers. ### Scenario based examples diff --git a/nexus-cancelation/README.md b/nexus-cancelation/README.md index c813eba11..6968aa5cb 100644 --- a/nexus-cancelation/README.md +++ b/nexus-cancelation/README.md @@ -1,6 +1,6 @@ # Nexus Cancellation -This sample shows how to cancel a Nexus operation from a caller workflow. +This sample shows how to cancel a Nexus operation from a caller workflow and specify a cancellation type. In this sample we will show using the `NexusOperationCancellationTypeWaitRequested` cancellation type, which allows the caller to return after the handler workflow has received the requested to be cancelled, but does not wait for the handler workflow to finish processing the cancellation request. For more details on Nexus and how to set up to run this sample, please see the [Nexus Sample](../nexus/README.md). diff --git a/nexus-cancelation/caller/workflows.go b/nexus-cancelation/caller/workflows.go index b7ccd3b07..1af692246 100644 --- a/nexus-cancelation/caller/workflows.go +++ b/nexus-cancelation/caller/workflows.go @@ -45,7 +45,14 @@ func HelloCallerWorkflow(ctx workflow.Context, name string) (string, error) { ctx, service.HelloOperationName, service.HelloInput{Name: name, Language: lang}, - workflow.NexusOperationOptions{}) + workflow.NexusOperationOptions{ + // Set the cancellation type to NexusOperationCancellationTypeWaitRequested. + // This means that the caller will wait for the cancellation request to be received by the handler before + // proceeding with the cancellation. + // + // By default, the caller would wait until the operation is completed. + CancellationType: workflow.NexusOperationCancellationTypeWaitRequested, + }) var output service.HelloOutput // This future gets resolved when the operation completes with either success, failure, timeout, // or cancelation. @@ -63,9 +70,12 @@ func HelloCallerWorkflow(ctx workflow.Context, name string) (string, error) { cancel() }) } - // Wait for all operations to resolve. Once the workflow completes, the server will stop trying to cancel any - // operations that have not yet received cancelation, letting them run to completion. It is totally valid to - // abandon operations for certain use cases. + // Wait for all operations futures to resolve. Once the workflow completes, + // the server will stop trying to cancel any operations that have not yet received cancelation, + // letting them run to completion. Since we set the CancellationType to NexusOperationCancellationTypeWaitRequested + // the future will be resolved when the operation receives the cancelation request. + // + // It is totally valid to abandon operations for certain use cases. wg.Wait(ctx) var greeting string diff --git a/nexus-cancelation/handler/app.go b/nexus-cancelation/handler/app.go index 65a8e5bdc..de2997702 100644 --- a/nexus-cancelation/handler/app.go +++ b/nexus-cancelation/handler/app.go @@ -9,6 +9,7 @@ import ( "github.com/nexus-rpc/sdk-go/nexus" "go.temporal.io/sdk/client" + "go.temporal.io/sdk/temporal" "go.temporal.io/sdk/temporalnexus" "go.temporal.io/sdk/workflow" @@ -37,7 +38,22 @@ func HelloHandlerWorkflow(ctx workflow.Context, input service.HelloInput) (servi return service.HelloOutput{}, err } if err := workflow.Sleep(ctx, duration); err != nil { - return service.HelloOutput{}, err + // Simulate some work after cancellation is requested + sleepErr := err + if temporal.IsCanceledError(err) { + ctx, _ = workflow.NewDisconnectedContext(ctx) + var duration time.Duration + err := workflow.SideEffect(ctx, func(ctx workflow.Context) any { + return time.Duration(rand.IntN(5)) * time.Second + }).Get(&duration) + if err != nil { + return service.HelloOutput{}, err + } + if err := workflow.Sleep(ctx, duration); err != nil { + return service.HelloOutput{}, err + } + } + return service.HelloOutput{}, sleepErr } switch input.Language {