I am almost embarrassed to even ask this question, but something doesn’t seem right.
Temporal 1.20.3, with Java SDK 1.19.1.
Imagine this super simple workflow:
@Override
public void execute() {
throw new RuntimeException("whoops");
}
When run, I’d expect this workflow to exit, and go into a failed state. That doesn’t happen. Instead, I get weird SDK errors re. replay, and the workflow stays in running state.
Either this is a bug, or I missed a memo somewhere. Any ideas?
This is by design. We don’t want workflows to fail on unexpected failures. It allows fixing them without losing workflows. Throw ApplicationFailure to fail the workflow.
. . . and it does the same thing – the workflow doesn’t go into a failed state.
Which gets me thinking. If an activity throws an exception and it’s not caught by the workflow, I’ll wager the workflow correctly goes into a failed state.
I should probably explain a little. Internally, the workflow is coded as a state-machine. If an error occurs, I am trying to figure out the best way to report the error (and/or an error-code). Querying the exception is probably a bad idea, because it means trawling the event-history. Probably saner to write the value(s) as search-attribute(s). In which case, we wouldn’t be throwing an exception, and it would just exit gracefully.
If you throw this failure from a workflow, it fails.
You probably threw this exception from an activity that by default, retries it. Either add this failure type to the list of RetryOptions.doNotRetry or throw ApplicationFailure.newNonRetryableFailure.
@sdonovan I cannot reproduce the problem you reported. If an ApplicationFailure is thrown from the child workflow the parent receives it and fails if it is not handled.
Did you specify a child workflow retry policy by any chance?
Took me a minute – was just trying a few cases. Problem was mine – passing back the null in:
newFailure("whoops", null)
. . . . was causing the problem. I hadn’t noticed it.
Short version is:
From an activity, you can throw either a RuntimeException (gets wrapped as an ApplicationFailure), or an ApplicationFailure. Because it’s always returned as an ApplicationFailure, if not caught by the workflow, it’ll cause the workflow to fail.
However, from a workflow, you can only emit ApplicationFailure exceptions, which will cause the workflow to fail. Throwing RuntimeException from workflow logic is NOT supported, and won’t cause the workflow to fail.
You can also configure your workflow to fail on any specific exception type (or on all if you configure Throwable as a type) by setting it in the WorkflowImplementationOptions.failWorkflowExceptionTypes.