feat: add cancel-in-progress sample#225
Conversation
|
Thanks for the contribution! To confirm, this example just starts a child workflow when the parent workflow starts and then waits for a signal to cancel the child workflow and start a new one? If I send 3 signals you start 3 children without waiting for any of the children to complete? Some notes:
Since this is essentially restart-child-on-signal, not sure it deserves an entire sample. But if so I think it could be simplified and clarified a bit. You might also want a test or two. For instance, make a test where you replicate the condition where the |
|
Hi, @cretz it would help a lot if you could point to the relevant places for your argumentation.
How so? A child workflow error will cancel the loop and return the error to the parent workflow
I don't think so. The cancellable context is created here https://github.com/temporalio/samples-go/pull/225/files#diff-e7190ffa6a984a8e3be3db5ad97758314062293387073e586d442ddd9d664b81R29
That's the whole idea of this sample. I'm only interested in the last signal.
Where can I find this example? |
No, I start a workflow with a signal. When another signal is sent during the execution of the child workflow the workflow is canceled and a new one is started with the options from the last available signal. |
|
👍 Will do full review... |
|
|
||
| import ( | ||
| "go.temporal.io/sdk/workflow" | ||
| "time" |
There was a problem hiding this comment.
I forget whether it's go fmt or goimports but may need to run them both so that stdlib imports are separate from others
| logger := workflow.GetLogger(ctx) | ||
|
|
||
| // Simulate some long running processing. | ||
| _ = workflow.Sleep(ctx, time.Second*3) |
There was a problem hiding this comment.
If you swallow this error this cannot get cancelled. It is important for our samples to show best practices of always responding to errors (if we haven't in other samples we should fix that)
| "go.temporal.io/sdk/workflow" | ||
| ) | ||
|
|
||
| const ParentWorkflowSignalName = "parent-workflow-signal" |
There was a problem hiding this comment.
IMO the signal name should reference what it does rather than who it's to, e.g. const RestartChildSignalName = "restart-child-signal"
|
|
||
| var message string | ||
|
|
||
| reBuildSignalChan := workflow.GetSignalChannel(ctx, ParentWorkflowSignalName) |
There was a problem hiding this comment.
What do you mean here by "build"?
| for !isProcessingDone { | ||
| ctx, cancelHandler := workflow.WithCancel(ctx) | ||
|
|
||
| // it is important to re-execute the child workflow after every signal |
There was a problem hiding this comment.
But you don't execute after every signal. If you get two signals you only execute after the latest. (seems to be by intention, just need to change this comment)
| func main() { | ||
| // The client is a heavyweight object that should be created only once per process. | ||
| c, err := client.Dial(client.Options{ | ||
| HostPort: client.DefaultHostPort, |
There was a problem hiding this comment.
The default can be left unset
| defer c.Close() | ||
|
|
||
| // This Workflow ID must be fixed because we don't want to start a new workflow every time. | ||
| projectID := "my-project" |
| var isProcessingDone = false | ||
|
|
||
| for !isProcessingDone { | ||
| ctx, cancelHandler := workflow.WithCancel(ctx) |
There was a problem hiding this comment.
For clarity reasons you might want rename ctx instead of shadowing the parent ctx. It can be unclear whether this is wrapping one from the previous loop iteration or not.
| } | ||
|
|
||
| if err != nil { | ||
| logger.Error("Child execution failure.", "Error", err) |
There was a problem hiding this comment.
You do this same log statement twice
| workflowID := "parent-workflow_" + projectID | ||
| workflowOptions := client.StartWorkflowOptions{ | ||
| ID: workflowID, | ||
| TaskQueue: "child-workflow", |
There was a problem hiding this comment.
To avoid clash w/ other samples, can you name this the name of the sample?
|
@cretz great review. I will address this soon. |
What was changed
This example demonstrates how to implement a workflow that ensures that only one run of the child workflow is executed at a time. Subsequent runs will cancel the running child workflow and re-run it with the latest sent options through
SignalWithStartWorkflow.Those semantics are useful, especially when implementing a CI pipeline. New commits during the workflow execution should short-circuit the child workflow and only build the most recent commit.
Why?
At WunderGraph, we use temporal to build our CI and CD platform. The solution has been implemented in collaboration with @mfateev I promised him to make a PR 😃
Checklist
Closes
How was this tested:
Manually, through the sample with a local temporal cluster.
I'm not familiar with the template boundaries
@@@SNIPSTARTin the samples. Please tell me the instructions.