11import  asyncio 
22import  time 
3- import  traceback 
43from  concurrent .futures  import  ThreadPoolExecutor 
54from  datetime  import  timedelta 
65from  typing  import  NoReturn 
@@ -19,9 +18,11 @@ def never_complete_activity() -> NoReturn:
1918        while  True :
2019            print ("Heartbeating activity" )
2120            activity .heartbeat ()
22-             time .sleep (1 )
23-     except  CancelledError :
24-         print ("Activity cancelled" )
21+             time .sleep (0.5 )
22+     except  CancelledError  as  err :
23+         print (
24+             f"Got exception in activity. Cause chain is { format_exception_cause_chain (err )}  
25+         )
2526        raise 
2627
2728
@@ -43,6 +44,11 @@ async def run(self) -> None:
4344                # Always set a heartbeat timeout for long-running activities 
4445                heartbeat_timeout = timedelta (seconds = 2 ),
4546            )
47+         except  Exception  as  err :
48+             print (
49+                 f"Got exception in workflow. Cause chain is { format_exception_cause_chain (err )}  
50+             )
51+             raise 
4652        finally :
4753            await  workflow .execute_activity (
4854                cleanup_activity , start_to_close_timeout = timedelta (seconds = 5 )
@@ -61,7 +67,6 @@ async def main():
6167        activities = [never_complete_activity , cleanup_activity ],
6268        activity_executor = ThreadPoolExecutor (5 ),
6369    ):
64- 
6570        # While the worker is running, use the client to start the workflow. 
6671        # Note, in many production setups, the client would be in a completely 
6772        # separate process from the worker. 
@@ -72,16 +77,25 @@ async def main():
7277        )
7378
7479        # Now that we've started, wait a couple of seconds then cancel it 
75-         await  asyncio .sleep (2 )
80+         await  asyncio .sleep (1 )
7681        await  handle .cancel ()
7782
7883        # Now wait on the result which we expect will fail since it was 
7984        # cancelled 
8085        try :
8186            await  handle .result ()
8287            raise  RuntimeError ("Should not succeed" )
83-         except  WorkflowFailureError :
84-             print ("Got expected exception: " , traceback .format_exc ())
88+         except  WorkflowFailureError  as  err :
89+             print (
90+                 f"Got expected exception in client. Cause chain is { format_exception_cause_chain (err )}  
91+             )
92+ 
93+ 
94+ def  format_exception_cause_chain (err : BaseException ) ->  str :
95+     causes  =  [err ]
96+     while  causes [- 1 ].__cause__ :
97+         causes .append (causes [- 1 ].__cause__ )
98+     return  " -> " .join ([f"{ e .__class__ .__name__ }   for  e  in  causes ])
8599
86100
87101if  __name__  ==  "__main__" :
0 commit comments