I have an update handler setup. After trimming it down a bit it essentially does the following
err = workflow.SetUpdateHandlerWithOptions(ctx, "StartChildWorkflow",
func(ctx workflow.Context, req StartWorkflowRequest) error {
futr := workflow.ExecuteChildWorkflow(ctx, req.WorkflowType, req.inputs...)
workflowState.MainLoop.AddFuture(futr, func(f workflow.Future) {
// todo if the worker instance is reset, this handler never fires
err := f.Get(ctx, nil)
if err != nil {
handleChildWorkflowErr(ctx, err)
}
workflowState.clearWorkflow()
})
workflowState.RunningWorkflow = true
workflowState.RunningWorkflowName = "dry-run"
workflowState.NumberOfCalls++
return nil
},
...
Where it starts a child workflow and adds its future to a selector. It works as expected under normal conditions. But if the worker is restarted while the child workflow is still running, the future never fires in the parent workflow.
A similar function (with no errors being returned) works in a signal handler.
workflowState.MainLoop.AddReceive(workflow.GetSignalChannel(ctx, "test"), func(c workflow.ReceiveChannel, more bool) {
Go 1.22.5
Temporal SDK 1.26.1 sdk module - go.temporal.io/sdk - Go Packages
Temporal Server 1.24.1 from the temporal
cli
I tried to replicate the scenario you described and I don’t experience any issue after restarting the worker. Can you provided a stand alone reproduction on the latest Go SDK release?
Thanks for checking on it.
Updated to latest. 1.28.1 workflow package - go.temporal.io/sdk/workflow - Go Packages
paired it down a bit further to this.
func HelloUpdates(ctx workflow.Context) error {
readyToDie := false
testState := 5
mainLoop := workflow.NewSelector(ctx)
err = workflow.SetQueryHandler(ctx, "test_state", func() (int, error) {
return testState, nil
})
if err != nil {
return errors.WithStack(err)
}
err = workflow.SetUpdateHandlerWithOptions(ctx, "sweet-update",
func(ctx workflow.Context) error {
fut := workflow.ExecuteChildWorkflow(ctx, HelloWorkflow)
mainLoop .AddFuture(fut, func(f workflow.Future) {
// if the instance is reset, this handler never fires
testState = 0
})
return nil
},
workflow.UpdateHandlerOptions{},
)
if err != nil {
return errors.WithStack(err)
}
for !readyToDie {
mainLoop .Select(ctx)
}
return nil
}
func HelloWorkflow(ctx workflow.Context) error {
_ = workflow.Sleep(ctx, 30*time.Second)
return nil
}
still not getting that state updated to 0 if I reset the worker in the middle.
actually, now I’ve done something where it doesn’t update the state even with the worker left running. Let me dig.
FWIW running this workflow, sending one update, then restarting the worker while the child workflow is running, after 30s the callback is called and testState
is updated.
Ok thanks for checking. Hmm. I guess at least I know the concept should work. Running that same example exactly I’m not getting the testState
update.
Confirming running v1.28.1 of the sdk and temporal cli v1.0.0 with server Server 1.24.2 run command temporal server start-dev --dynamic-config-value=frontend.enableUpdateWorkflowExecution=true
Well. I’ve tried a few things, not sure why it isn’t working for me. I think for now I’ll just skip using the select statement and rewrite the handler using a temporal goroutine.
func(ctx workflow.Context) error {
fut := workflow.ExecuteChildWorkflow(ctx, HelloWorkflow)
fmt.Println("handler firing")
fmt.Printf("%v handler firing\n", fut)
workflow.Go(ctx, func(ctx workflow.Context) {
_ = fut.Get(ctx, nil)
fmt.Println("finally")
testState = 5
})
return nil
},