Error handling in workloads and when sending signals

Hi, let me just apologise in advance if this is something that has already been discussed, I have looked for similar discussions but have to found something I understood correctly.

Basically I have 2 questions regarding error handling in 2 different temporal scenarios.

(1) Lets say my workflow asks a repository for an entity by an ID. For example, lets say the workflow starts by checking if an Order with ID “abc” exists. A common way for repos to answer is with an error, something like “fmt.Errorf(“this entity %s does not exist”, entityID)”. If I in my workflow code want to react to this error, my first naive approach was to use Gos errors.Is(err, repoErr). However I understand now that this is not possible since temporal wrap the errors with metadata (correct me If I’m wrong). Atm I solve this by making the function that uses the repo return an empty entity instead of a error, and then in the workflow I check if the entity is empty. Is there a more elegant solution here. Something like workflow.Is(err, realErr) or something similar ? Any suggestion is welcome!

(2)
I would like to do something like below

. Basically if a signal fails because a workflow was already finished the don’t treat it as an error. I’m unable to find where EntityNotExistsError is defined and not sure if this is the way to go about it.

Sry for my ignorance :slight_smile:

(1) Use ApplicaitonError to return errors that need special handling in the workflow. Use ApplicationError.Type() to discriminate between different error types.

Activity:

func Activity(...) (string, error) {
        ...
	return "", temporal.NewApplicationError(fmt.Sprintf("this entity %s does not exist", entityID), "EntityNotExists", entityID)
}

Workflow:

	err := workflow.ExecuteActivity(ctx, Activity, name).Get(ctx, &result)
	if err != nil {
		switch cause := errors.Unwrap(err); cause.(type) {
		case *temporal.ApplicationError:
			switch cause.(*temporal.ApplicationError).Type() {
			case "EntityNotExists":
				// handle not exists
			default:
				// handle other app error
			}
		case *temporal.TimeoutError:
			// handle timeout
		default:
			// handle other error types
		}
		...
	}
1 Like

(2) The error is serviceerror.NotFound:

	err = c.SignalWorkflow(context.Background(), ...)
	if err != nil {
		switch err.(type) {
		case *serviceerror.NotFound:
			log.Fatalln("NotFoundError", err)
		default:
			log.Fatalln("Error", err)
		}
	}
1 Like

Perfect, thanks !