@@ -1202,45 +1202,53 @@ async def _run_top_level_workflow_function(self, coro: Awaitable[None]) -> None:
12021202 except _ContinueAsNewError as err :
12031203 logger .debug ("Workflow requested continue as new" )
12041204 err ._apply_command (self ._add_command ())
1205- except temporalio .exceptions .FailureError as err :
1205+
1206+ # Note in some Python versions, cancelled error does not extend
1207+ # exception
1208+ # TODO(cretz): Should I fail the task on BaseException too (e.g.
1209+ # KeyboardInterrupt)?
1210+ except (Exception , asyncio .CancelledError ) as err :
12061211 logger .debug (
12071212 f"Workflow raised failure with run ID { self ._info .run_id } " ,
12081213 exc_info = True ,
12091214 )
1210- # If a cancel was requested, and the failure is from an activity or
1211- # child, and its cause was a cancellation, we want to use that cause
1212- # instead because it means a cancel bubbled up while waiting on an
1213- # activity or child.
1214- if (
1215- self ._cancel_requested
1216- and (
1217- isinstance (err , temporalio .exceptions .ActivityError )
1218- or isinstance (err , temporalio .exceptions .ChildWorkflowError )
1219- )
1220- and isinstance (err .cause , temporalio .exceptions .CancelledError )
1221- ):
1222- err = err .cause
12231215
1224- command = self ._add_command ()
1225- command .fail_workflow_execution .failure .SetInParent ()
1226- try :
1227- self ._failure_converter .to_failure (
1228- err ,
1229- self ._payload_converter ,
1230- command .fail_workflow_execution .failure ,
1216+ # All asyncio cancelled errors become Temporal cancelled errors
1217+ if isinstance (err , asyncio .CancelledError ):
1218+ err = temporalio .exceptions .CancelledError (str (err ))
1219+
1220+ # If a cancel was ever requested and this is a cancellation, or an
1221+ # activity/child cancellation, we add a cancel command. Technically
1222+ # this means that a swallowed cancel followed by, say, an activity
1223+ # cancel later on will show the workflow as cancelled. But this is
1224+ # a Temporal limitation in that cancellation is a state not an
1225+ # event.
1226+ if self ._cancel_requested and (
1227+ isinstance (err , temporalio .exceptions .CancelledError )
1228+ or (
1229+ (
1230+ isinstance (err , temporalio .exceptions .ActivityError )
1231+ or isinstance (err , temporalio .exceptions .ChildWorkflowError )
1232+ )
1233+ and isinstance (err .cause , temporalio .exceptions .CancelledError )
12311234 )
1232- except Exception as inner_err :
1233- raise ValueError ("Failed converting workflow exception" ) from inner_err
1234- except asyncio .CancelledError as err :
1235- command = self ._add_command ()
1236- command .fail_workflow_execution .failure .SetInParent ()
1237- self ._failure_converter .to_failure (
1238- temporalio .exceptions .CancelledError (str (err )),
1239- self ._payload_converter ,
1240- command .fail_workflow_execution .failure ,
1241- )
1242- except Exception as err :
1243- self ._current_activation_error = err
1235+ ):
1236+ self ._add_command ().cancel_workflow_execution .SetInParent ()
1237+ elif isinstance (err , temporalio .exceptions .FailureError ):
1238+ # All other failure errors fail the workflow
1239+ failure = self ._add_command ().fail_workflow_execution .failure
1240+ failure .SetInParent ()
1241+ try :
1242+ self ._failure_converter .to_failure (
1243+ err , self ._payload_converter , failure
1244+ )
1245+ except Exception as inner_err :
1246+ raise ValueError (
1247+ "Failed converting workflow exception"
1248+ ) from inner_err
1249+ else :
1250+ # All other exceptions fail the task
1251+ self ._current_activation_error = err
12441252
12451253 async def _signal_external_workflow (
12461254 self ,
@@ -1471,7 +1479,7 @@ async def handle_query(self, input: HandleQueryInput) -> Any:
14711479 # an # interceptor could have changed the name
14721480 if not handler :
14731481 raise RuntimeError (
1474- f"Query handler for { input .query } expected but not found"
1482+ f"Query handler for ' { input .query } ' expected but not found"
14751483 )
14761484 # Put name first if dynamic
14771485 args = list (input .args ) if not dynamic else [input .query ] + list (input .args )
0 commit comments