Hi, I am unable to return a slice or pointer to slice from temporal activity
Here is the sample code
type Workload struct {
CreatedAt time.Time `cql:"created_at" json:"created_at"`
ID gocql.UUID `cql:"id" json:"id"`
Kind string `cql:"kind" json:"kind"`
Name string `cql:"name" json:"name"`
UpdatedAt time.Time `cql:"updated_at" json:"updated_at"`
}
func (a *Activities) GetWorkloads(ctx context.Context, stackID string) ([]Workload, error) {
wl := make([]Workload, 0)
params := db.QueryParams{"stack_id": stackID}
if err := db.Filter(&Workload{}, &wl, params); err != nil {
return nil, err
}
shared.Logger.Debug("GetWorkloads", "workloads", wl)
return wl, nil
}
// snippet of workload executing activity and getting result
future = workflow.ExecuteActivity(act, activities.GetWorkloads, stackID)
selector.AddFuture(future, func(f workflow.Future) {
var wl []Workload
future.Get(ctx, wl)
logger.Info("GetWorkloads activity complete", "workloads", wl)
})
The debug log line inside the activity prints the valid data received from DB and the temporal UI also shows that data in the activity results but when I log the activity result received in workload, it’s always empty
I have tried many other options like returning a pointer to Workload, defining a type []
Workload and returning this type or it’s pointer, creating wl with and without make but nothing is working.
I haven’t found any example activity returning slice in temporal sample programs.
Hi Amna,
You need to use pointer to receive value, e.g. future.Get(ctx, &wl)
.
The go sdk does return error when non-pointer is passed into Get. But your code ignores it. I’d do something like:
selector.AddFuture(future, func(f workflow.Future) {
var wl []Workload
errGet := f.Get(ctx, &wl)
if errGet != nil {
err = fmt.Errorf("failed to get activity result: %w", errGet)
return
}
logger.Info("GetWorkloads activity complete", "workloads", wl)
})
Hi @taonic
Thanks for your response. I had already tried with pointer but the result is same. I tried it again after your reply, here is the updated code
var wl []Workload
future = workflow.ExecuteActivity(act, activities.GetWorkloads, stackID)
selector.AddFuture(future, func(f workflow.Future) {
errGet := future.Get(ctx, &wl)
if errGet != nil {
logger.Error("failed to get activity result", "errGet", errGet)
}
logger.Info("GetWorkloads activity complete", "workloads", wl)
})
and the corresponding log lines
GetWorkloads activity complete {"Namespace": "default", "TaskQueue": "core", "WorkerID": "5432@DESKTOP-25ABC2V@", "WorkflowType": "GetAssetsWorkflow", "WorkflowID": "ai.ctrlplane.core.getAssets.stack.fd13258c-b00e-4e66-a72f-2b7ecc59632b", "RunID": "51c6d28b-b493-441b-b0cf-d1fcbbfa932b", "Attempt": 1, "workloads": null}
The behavior is same after returning the pointer from activity too
func (a *Activities) GetWorkloads(ctx context.Context, stackID string) (*[]Workload, error) {
wl := make([]Workload, 0)
params := db.QueryParams{"stack_id": stackID}
if err := db.Filter(&Workload{}, &wl, params); err != nil {
return nil, err
}
shared.Logger.Debug("GetWorkloads", "workloads", wl)
return &wl, nil
}
Oh, another typo I also missed previously is to use f.Get
instead of future.Get
inside selector.AddFuture(future, func(f workflow.Future)
. I have corrected my code above. Not sure if this would solve your problem tho.
The problem is resolved by wrapping the slice in struct and returning that struct