Child workflow still keeps retrying when its activity caught non retryable error

I have a child workflow running an activity. Inside the activity, it throws non-retryable application error. The child workflow fails only for that execution run. Its retry state is still Retry State In Progress. And it spins up a new execution run immediately.

Is this expected? How to stop the child workflow from retrying in such case?

Did you set retry options for the child?

Yes. I set the RetryPolicy as below and WorkflowExecutionTimeout to 30 min.

&temporal.RetryPolicy{
InitialInterval: 1 * time.Second,
MaximumInterval: 1 * time.Second,
MaximumAttempts: 0,
},

This is that failed child workflow result. The activity is RETRY_STATE_NON_RETRYABLE_FAILURE, while the child workflow is still RETRY_STATE_IN_PROGRESS

The nonretryable failure is thrown from the activity, and the activity is not retried. The workflow receives it wrapped in an ActivityFailure, which is retryable. If you want to the workflow to retry you should throw an NonRetryable failure from the workflow directly.

1 Like

@maxim The child workflow is still retrying with this code.

func (w Worker) MyChildWorkflow(
  ...
) (
  ...
) {
	err := workflow.ExecuteActivity(ctx, MyActivity, ...).Get(ctx, nil)
	if err != nil {
		var applicationErr *temporal.ApplicationError
			if errors.As(err, &applicationErr) {
				if applicationErr.NonRetryable() {
					err = temporal.NewNonRetryableApplicationError("activity failed", "NonRetryableFailure", err)
				}
			}
		return
	}
}

Your code worked for me. This is the error that caused the child workflow to fail without retrying.

{
  "message": "activity failed",
  "source": "GoSDK",
  "cause": {
    "message": "activity error",
    "source": "GoSDK",
    "cause": {
      "message": "simulated activity error",
      "source": "GoSDK",
      "applicationFailureInfo": {
        "type": "Simulated",
        "nonRetryable": true
      }
    },
    "activityFailureInfo": {
      "scheduledEventId": "8",
      "startedEventId": "9",
      "identity": "93992@Maxims-MacBook-Pro.local@",
      "activityType": {
        "name": "ChildActivity"
      },
      "activityId": "8",
      "retryState": "RETRY_STATE_NON_RETRYABLE_FAILURE"
    }
  },
  "applicationFailureInfo": {
    "type": "NonRetryableFailure",
    "nonRetryable": true
  }
}

@maxim Thanks for checking! I think I kind of realized the issue. In my code, it didn’t even get to this err = temporal.NewNonRetryableApplicationError("activity failed", "NonRetryableFailure", err) line of code. I’m getting below from the child workflow result in temporal UI. So looks like errors.As(err, &applicationErr) returns false?

{
  "message": "activity error",
  "source": "GoSDK",
  "cause": {
    "message": "xxx",
    "source": "GoSDK",
    "cause": {
      "message": "xxx",
      "source": "GoSDK",
      "applicationFailureInfo": {}
    },
    "applicationFailureInfo": {
      "type": "InvalidParameter",
      "nonRetryable": true
    }
  },
  "activityFailureInfo": {
    "scheduledEventId": "11",
    "startedEventId": "12",
    "identity": "xxx",
    "activityType": {
      "name": "xxx"
    },
    "activityId": "11",
    "retryState": "RETRY_STATE_NON_RETRYABLE_FAILURE"
  }
}
1 Like

This is my code: Comparing temporalio:main...mfateev:error-handling · temporalio/samples-go · GitHub

1 Like

Issue solved finally. That code actually works for me as well. Thanks for addressing this

1 Like