fix(testing): handle workflow failure states correctly - #682
Conversation
f4129a2 to
b6a604a
Compare
b6a604a to
861756a
Compare
861756a to
09acaf6
Compare
| self._complete_workflow( | ||
| execution_arn, result=None, error=response.error | ||
| ) | ||
| self._fail_workflow(execution_arn, response.error) |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
There was a problem hiding this comment.
There is one small obstacle to doing that. There currently isn't anything in the public API of DurableFunctionTestRunner or DurableFunctionTestResult that exposes an execution's status in the emulator. The public runner result only exposes the returned durable invocation status/result, not execution.
We could use private internals, like DurableFunctionTestRunner._executor, to get execution information, but that feels hacky to me for an e2e style test.
If we want to add an e2e test for this case, then I think we should first add a small public runner accessor for execution details/status, then use that in the test.
There was a problem hiding this comment.
I feel like we should expose a method for the overall execution status on the test runner here. Do we have this in the TS testing library? Thinking something like result.execution_status?
There was a problem hiding this comment.
nice idea @bchampp :-)
result.execution_status sourced from close_status
This comment has been minimized.
This comment has been minimized.
Codex AI reviewNo actionable findings. Tests were not run per review constraints; residual risk is limited to unexecuted runtime integration coverage. Reviewed commit |
| self._complete_workflow( | ||
| execution_arn, result=None, error=response.error | ||
| ) | ||
| self._fail_workflow(execution_arn, response.error) |
There was a problem hiding this comment.
I feel like we should expose a method for the overall execution status on the test runner here. Do we have this in the TS testing library? Thinking something like result.execution_status?
yaythomas
left a comment
There was a problem hiding this comment.
Very nice, thank you! just some nits.
| stored = store.load(execution.durable_execution_arn) | ||
| assert stored.is_complete is True | ||
| assert stored.close_status is not None | ||
| assert stored.close_status.value == "FAILED" |
There was a problem hiding this comment.
you can compare enums directly
assert stored.close_status is ExecutionStatus.FAILED
| assert stored.close_status is not None | ||
| assert stored.close_status.value == "FAILED" | ||
| assert stored.result is not None | ||
| assert stored.result.status == InvocationStatus.FAILED |
There was a problem hiding this comment.
assert stored.result.status is InvocationStatus.FAILED
| assert result.result == json.dumps("handled") | ||
|
|
||
| child_op: ContextOperation = result.get_context("failing-child") | ||
| assert child_op.status == OperationStatus.FAILED |
There was a problem hiding this comment.
child_op.status is OperationStatus.FAILED
| execution.complete_fail(None) | ||
|
|
||
| assert execution.is_complete is True | ||
| assert execution.result.status == InvocationStatus.FAILED |
There was a problem hiding this comment.
execution.result.status is InvocationStatus.FAILED
| self._complete_workflow( | ||
| execution_arn, result=None, error=response.error | ||
| ) | ||
| self._fail_workflow(execution_arn, response.error) |
There was a problem hiding this comment.
nice idea @bchampp :-)
result.execution_status sourced from close_status
| self.complete_execution(execution_arn, result) | ||
|
|
||
| def on_failed(self, execution_arn: str, error: ErrorObject) -> None: | ||
| def on_failed(self, execution_arn: str, error: ErrorObject | None) -> None: |
There was a problem hiding this comment.
This type widening is right, and it exposes a pre-existing emulator divergence... Common typing W.
The checkpoint EXECUTION FAIL processor (checkpoint/processors/execution.py) synthesizes a generic ErrorObject when the update has no error, but it should instead preserve null there.
Proposal: remove the synthetic fallback, and widen ExecutionNotifier.notify_failed + ExecutionObserver.on_failed to ErrorObject | None to match the widened null signature.
Issue #, if available:
#656
Description of changes:
self._fail_workflow()instead ofself._complete_workflow()so that executions fail despite not having an error payloadTesting:
hatch run test:allBy submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.