1
1
import asyncio
2
2
import time
3
- import traceback
4
3
from concurrent .futures import ThreadPoolExecutor
5
4
from datetime import timedelta
6
5
from typing import NoReturn
@@ -19,9 +18,11 @@ def never_complete_activity() -> NoReturn:
19
18
while True :
20
19
print ("Heartbeating activity" )
21
20
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
+ )
25
26
raise
26
27
27
28
@@ -43,6 +44,11 @@ async def run(self) -> None:
43
44
# Always set a heartbeat timeout for long-running activities
44
45
heartbeat_timeout = timedelta (seconds = 2 ),
45
46
)
47
+ except Exception as err :
48
+ print (
49
+ f"Got exception in workflow. Cause chain is { format_exception_cause_chain (err )} "
50
+ )
51
+ raise
46
52
finally :
47
53
await workflow .execute_activity (
48
54
cleanup_activity , start_to_close_timeout = timedelta (seconds = 5 )
@@ -61,7 +67,6 @@ async def main():
61
67
activities = [never_complete_activity , cleanup_activity ],
62
68
activity_executor = ThreadPoolExecutor (5 ),
63
69
):
64
-
65
70
# While the worker is running, use the client to start the workflow.
66
71
# Note, in many production setups, the client would be in a completely
67
72
# separate process from the worker.
@@ -72,16 +77,25 @@ async def main():
72
77
)
73
78
74
79
# Now that we've started, wait a couple of seconds then cancel it
75
- await asyncio .sleep (2 )
80
+ await asyncio .sleep (1 )
76
81
await handle .cancel ()
77
82
78
83
# Now wait on the result which we expect will fail since it was
79
84
# cancelled
80
85
try :
81
86
await handle .result ()
82
87
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 ])
85
99
86
100
87
101
if __name__ == "__main__" :
0 commit comments