Skip to content

Commit 0019cb8

Browse files
committed
Treat TimeoutError as workflow/update failure instead of task failure
Fixes temporalio#798
1 parent 49ca10e commit 0019cb8

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

temporalio/worker/_workflow_instance.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,10 +1708,11 @@ def _instantiate_workflow_object(self) -> Any:
17081708

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

tests/worker/test_workflow.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6990,3 +6990,34 @@ async def test_update_handler_semaphore_acquisition_respects_timeout(
69906990
ever_in_critical_section=3, peak_in_critical_section=3
69916991
),
69926992
)
6993+
6994+
@workflow.defn
6995+
class TimeoutErrorWorkflow:
6996+
@workflow.run
6997+
async def run(self, scenario) -> None:
6998+
if scenario == "workflow.wait_condition":
6999+
await workflow.wait_condition(lambda: False, timeout=0.01)
7000+
elif scenario == "asyncio.wait_for":
7001+
await asyncio.wait_for(asyncio.sleep(1000), timeout=0.01)
7002+
elif scenario == "asyncio.timeout":
7003+
async with asyncio.timeout(0.1):
7004+
await asyncio.sleep(1000)
7005+
else:
7006+
raise RuntimeError("Unrecognized scenario")
7007+
7008+
async def test_workflow_timeout_error(client: Client):
7009+
async with new_worker(client, TimeoutErrorWorkflow) as worker:
7010+
scenarios = ["workflow.wait_condition", "asyncio.wait_for"]
7011+
if sys.version_info >= (3, 11):
7012+
scenarios.append("asyncio.timeout")
7013+
7014+
for scenario in scenarios:
7015+
with pytest.raises(WorkflowFailureError) as err:
7016+
await client.execute_workflow(
7017+
TimeoutErrorWorkflow.run,
7018+
scenario,
7019+
id=f"workflow-{uuid.uuid4()}",
7020+
task_queue=worker.task_queue,
7021+
)
7022+
assert isinstance(err.value.cause, ApplicationError)
7023+
assert err.value.cause.type == "TimeoutError"

0 commit comments

Comments
 (0)