Skip to content

Commit fb3dccd

Browse files
authored
Treat TimeoutError as workflow/update failure instead of task failure (#800)
Fixes #798
1 parent 1296cd7 commit fb3dccd

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

temporalio/worker/_workflow_instance.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1712,10 +1712,11 @@ def _instantiate_workflow_object(self) -> Any:
17121712

17131713
def _is_workflow_failure_exception(self, err: BaseException) -> bool:
17141714
# An exception is a failure instead of a task fail if it's already a
1715-
# failure error or if it is an instance of any of the failure types in
1716-
# the worker or workflow-level setting
1715+
# failure error or if it is a timeout error or if it is an instance of
1716+
# any of the failure types in the worker or workflow-level setting
17171717
return (
17181718
isinstance(err, temporalio.exceptions.FailureError)
1719+
or isinstance(err, asyncio.TimeoutError)
17191720
or any(isinstance(err, typ) for typ in self._defn.failure_exception_types)
17201721
or any(
17211722
isinstance(err, typ)

tests/worker/test_workflow.py

+34
Original file line numberDiff line numberDiff line change
@@ -6923,6 +6923,40 @@ async def test_update_handler_semaphore_acquisition_respects_timeout(
69236923
)
69246924

69256925

6926+
@workflow.defn
6927+
class TimeoutErrorWorkflow:
6928+
@workflow.run
6929+
async def run(self, scenario) -> None:
6930+
if scenario == "workflow.wait_condition":
6931+
await workflow.wait_condition(lambda: False, timeout=0.01)
6932+
elif scenario == "asyncio.wait_for":
6933+
await asyncio.wait_for(asyncio.sleep(1000), timeout=0.01)
6934+
elif scenario == "asyncio.timeout":
6935+
if sys.version_info >= (3, 11):
6936+
async with asyncio.timeout(0.1):
6937+
await asyncio.sleep(1000)
6938+
else:
6939+
raise RuntimeError("Unrecognized scenario")
6940+
6941+
6942+
async def test_workflow_timeout_error(client: Client):
6943+
async with new_worker(client, TimeoutErrorWorkflow) as worker:
6944+
scenarios = ["workflow.wait_condition", "asyncio.wait_for"]
6945+
if sys.version_info >= (3, 11):
6946+
scenarios.append("asyncio.timeout")
6947+
6948+
for scenario in scenarios:
6949+
with pytest.raises(WorkflowFailureError) as err:
6950+
await client.execute_workflow(
6951+
TimeoutErrorWorkflow.run,
6952+
scenario,
6953+
id=f"workflow-{uuid.uuid4()}",
6954+
task_queue=worker.task_queue,
6955+
)
6956+
assert isinstance(err.value.cause, ApplicationError)
6957+
assert err.value.cause.type == "TimeoutError"
6958+
6959+
69266960
def check_in_workflow() -> str:
69276961
return "in workflow" if workflow.in_workflow() else "not in workflow"
69286962

0 commit comments

Comments
 (0)