Returning slice or pointer to slice from activity

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