Set HeartbeatTimeout with WithActivityOptions in a child workflow

We want to be able to set WaitForCancellation to true using workflow.WithChildOptions when starting a Child workflow and then within the child workflow configure the HeartbeatTimeout using workflow.WithActivityOptions.

The behavior we see is that this combination of calls does not allow setting the HeartbeatTimeout and instead the value is always 0 in the child activities. If we don’t try to set WaitForCancellation with a call to workflow.WithChildOptions when starting the child workflow then the HeartbeatTimeout gets set as expected.

I don’t see how parent workflow child workflow options can affect heartbeat configuration of the child one. Could you provide the reproduction (or at least a code snippet) to explain what you are doing in more detail?

Agreed. Hopefully something simple on our end.

from tctl:
“serverVersion”: “1.5.1”

from go.mod:
go.temporal.io/api v1.4.0
go.temporal.io/sdk v1.4.1

Sample parent and child:

    func SampleChildWorkflow(ctx workflow.Context, name string) (string, error) {

    	ao := workflow.ActivityOptions{
    		StartToCloseTimeout: time.Minute * 1,
    		HeartbeatTimeout:    time.Second * 9,
    		WaitForCancellation: true,
    		ActivityID:          "sample-activity-id",
    	}

    	ctx = workflow.WithActivityOptions(ctx, ao)

    	var greeting string
    	err := workflow.ExecuteActivity(ctx, GreetingActivity, name).Get(ctx, &greeting)
    	return greeting, err
    }

    func GreetingActivity(ctx context.Context, name string) (string, error) {
    	greeting := "Hello " + name + "!"
    	return greeting, nil
    }

func SampleParentWorkflow(ctx workflow.Context, name string) (string, error) {
	logger := workflow.GetLogger(ctx)

    // Removing these two lines produces expected results
	cwo := workflow.ChildWorkflowOptions{}
	ctx = workflow.WithChildOptions(ctx, cwo)

	var result string
	err := workflow.ExecuteChildWorkflow(ctx, SampleChildWorkflow, name).Get(ctx, &result)
	if err != nil {
		logger.Error("Parent execution received child execution failure.", "Error", err)
		return "", err
	}
	logger.Info("Parent execution completed.", "Result", result)
	return result, nil
}

Heartbeat Timeout not set in history, but other fields are like StartToClose and ActivityID:

Got it sorted. Seems both parent and child workflows need WorkflowExecutionTimeout set in StartWorkflowOptions and ChildWorkflowOptions when starting or the heartbeatTimeout will be 0 for activities regardless of value set in workflow.ActivityOptions.

WorkflowExecutionTimeout is listed as optional but seems like it does have unexpected side effect for us.

This is certainly not the way it is expected to work. Let us look into this.