Hello,
I’m making a workflow where I want to run a batch in parallel, running around 15 activities at the same time and waiting for the result to complete before proceeding.
I have been using the following code to run these activities:
selector := workflow.NewSelector(ctx)
links := []string{...links} // insert links here
results := []string{}
childCtx, cancelHandler := workflow.WithCancel(ctx)
var batchErr error
for i, v := range links {
v := v
future := workflow.ExecuteActivity(childCtx, activities.ProcessLinks, v)
selector.AddFuture(future, func(f workflow.Future) {
var result string
if err := f.Get(ctx, &result); err != nil {
cancelHandler()
batchErr = fmt.Errorf("ProcessLinks(%s): %w", v, err)
}
results = append(results, result)
})
}
for i := 0; i < len(links); i++ {
selector.Select(ctx)
if batchErr != nil {
return "", batchErr
}
}
// continue from here with the results
But I also looked the ‘DSL’ example here: https://github.com/temporalio/samples-go/blob/main/dsl/workflow.go
and I noticed it uses workflow.Go instead:
selector := workflow.NewSelector(ctx)
links := []string{...links} // insert links here
results := []string{}
childCtx, cancelHandler := workflow.WithCancel(ctx)
var batchErr error
for i, v := range links {
v := v
future, settable := workflow.NewFuture(childCtx)
workflow.Go(childCtx, func(futCtx workflow.Context) {
var result string
err := workflow.ExecuteActivity(futCtx, activities.ProcessLinks, v).Get(futCtx, &result)
settable.Set(result, err)
})
selector.AddFuture(future, func(f workflow.Future) {
var result string
if err := f.Get(ctx, &result); err != nil {
cancelHandler()
batchErr = fmt.Errorf("ProcessLinks(%s): %w", v, err)
}
results = append(results, result)
})
}
for i := 0; i < len(links); i++ {
selector.Select(ctx)
if batchErr != nil {
return "", batchErr
}
}
// continue from here with the results
Which is the correct and canonical way to do this? Since AddFuture accepts a future and, I’m assuming, puts this event into the history anyway, what is the benefit of using a goroutine?
Also as a separate question, do I need to defer
cancelHandler, like in Go?