Do activity input params stay the same during workflow replay?

I have a workflow and activity setup as following

type Rollback struct {
	Product   string
	RequestID string
}

type RollbackList []Rollback

type ActivityRequest struct {
	Name         string
	RollbackList RollbackList
}

func (w Workflow) RollbackWorkflow(ctx workflow.Context, rollbackList RollbackList) error {
	ao := workflow.ActivityOptions{
		StartToCloseTimeout: defaultActivityTimeout,
	}
	ctx = workflow.WithActivityOptions(ctx, ao)
	logger := workflow.GetLogger(ctx)

	logger.Info("Starting activity")

	for i := range rollbackList {
		rollbackList[i].RequestID = uuid.New().String()
	}
	activityRequest := ActivityRequest{
		Name:         "rollback",
		RollbackList: rollbackList,
	}
	err := workflow.ExecuteActivity(ctx, DeleteProducts, activityRequest).Get(ctx, nil)
	if err != nil {
		return err
	}
	logger.Info("Finished activity")

	return nil
}

type Activity struct {
	productReportsClient productReports.Client
}

func (a Activity) DeleteProducts(ctx context.Context, req ActivityRequest) (string, error) {

	for _, rollback := range req.RollbackList {
		_, err := a.productReportsClient.DeleteWithContext(
			invocationcontext.NewContext(ctx, invocationcontext.FromActivityContext(ctx)),
			rollback.Product,
			&productReports.DeleteParams{RequestId: &rollback.RequestID},
		)
		if err != nil {
			return "", err
		}
	}
	return "", nil
}

Here I am generating uuid rollbackList[i].RequestID = uuid.New().String() inside the workflow and assigning it to the data that I will be passing in for activity input ActivityRequest.

Let’s assume, activity failed, it keeps on retrying but fails every time. Now, if I redeploy a new version of the service and that replay the workflow.

Does it generate NEW UUID to be passed in for activity input ActivityRequest? OR It keeps the same input for activity with OLD UUID (from failed attempt) during replay by getting it from event history?

I am unable to verify it locally with testing.

The input arguments of an activity are not checked during replay. So this code is safe. The input of the activity is recorded when it is invoked, so all retries will always use the same input.

One common issue with using random UUIDs is when they are used as child workflow IDs. This breaks determinism.

Thank you for the quick response.

So if uuid is not used to generate workflowId/RunID/EventID/ActivityID kind of things, and just used to pass as activity input, input stays the same (deterministic) even during the workflow replay right?

Let’s assume Workflow generated uuid to be c04547d4-1e30-4251-9ea5-95b84e394c95 and passed it as an activity argument for DeleteProducts activity,
Here in both the case,

  1. Activity retries (if failed)
  2. Workflow replay triggering activity execution again

will have the same requestID c04547d4-1e30-4251-9ea5-95b84e394c95 since that gets data from recorded event history, correct?

Input doesn’t stay the same during replay. But the input passed to an already invoked activity is ignored.

Ahhh. So even if we generate and pass new uuid to the input, it is ignored and uuid from recorded event will be used here during replay.

1 Like

It is not really used during replay. The activity retry doesn’t require replay.

Makes sense. This was helpful. Thank you for the explanation.