33import json
44from dataclasses import replace
55from datetime import UTC , datetime
6- from typing import TYPE_CHECKING
6+ from typing import TYPE_CHECKING , Any
77from uuid import uuid4
88
99from aws_durable_execution_sdk_python .execution import (
1010 DurableExecutionInvocationOutput ,
1111 InvocationStatus ,
1212)
1313from aws_durable_execution_sdk_python .lambda_service import (
14+ CallbackOptions ,
15+ ContextOptions ,
1416 ErrorObject ,
1517 ExecutionDetails ,
18+ InvokeOptions ,
1619 Operation ,
20+ OperationAction ,
1721 OperationStatus ,
22+ OperationSubType ,
1823 OperationType ,
1924 OperationUpdate ,
25+ StepOptions ,
26+ WaitOptions ,
2027)
2128
2229# Import AWS exceptions
2734from aws_durable_execution_sdk_python_testing .token import CheckpointToken
2835
2936
37+ def _operation_update_from_dict (data : dict [str , Any ]) -> OperationUpdate :
38+ """Create OperationUpdate from dictionary data."""
39+ error = ErrorObject .from_dict (data ["Error" ]) if data .get ("Error" ) else None
40+
41+ context_options = None
42+ if context_data := data .get ("ContextOptions" ):
43+ context_options = ContextOptions (
44+ replay_children = context_data .get ("ReplayChildren" , False )
45+ )
46+
47+ step_options = None
48+ if step_data := data .get ("StepOptions" ):
49+ step_options = StepOptions (
50+ next_attempt_delay_seconds = step_data .get ("NextAttemptDelaySeconds" )
51+ )
52+
53+ wait_options = None
54+ if wait_data := data .get ("WaitOptions" ):
55+ wait_options = WaitOptions .from_dict (wait_data )
56+
57+ callback_options = None
58+ if callback_data := data .get ("CallbackOptions" ):
59+ callback_options = CallbackOptions (
60+ timeout_seconds = callback_data .get ("TimeoutSeconds" ),
61+ heartbeat_timeout_seconds = callback_data .get ("HeartbeatTimeoutSeconds" ),
62+ )
63+
64+ invoke_options = None
65+ if invoke_data := data .get ("InvokeOptions" ):
66+ invoke_options = InvokeOptions (
67+ function_name = invoke_data .get ("FunctionName" , "" ),
68+ timeout_seconds = invoke_data .get ("TimeoutSeconds" ),
69+ )
70+
71+ return OperationUpdate (
72+ operation_id = data ["Id" ],
73+ operation_type = OperationType (data ["Type" ]),
74+ action = OperationAction (data ["Action" ]),
75+ parent_id = data .get ("ParentId" ),
76+ name = data .get ("Name" ),
77+ sub_type = OperationSubType (data ["SubType" ]) if data .get ("SubType" ) else None ,
78+ payload = data .get ("Payload" ),
79+ error = error ,
80+ context_options = context_options ,
81+ step_options = step_options ,
82+ wait_options = wait_options ,
83+ callback_options = callback_options ,
84+ invoke_options = invoke_options ,
85+ )
86+
87+
3088if TYPE_CHECKING :
3189 from aws_durable_execution_sdk_python_testing .model import (
3290 StartDurableExecutionInput ,
@@ -51,7 +109,7 @@ def __init__(
51109 # TODO: this will need to persist/rehydrate depending on inmemory vs sqllite store
52110 self .token_sequence : int = 0
53111 self .is_complete : bool = False
54- self .result : DurableExecutionInvocationOutput | None
112+ self .result : DurableExecutionInvocationOutput | None = None
55113 self .consecutive_failed_invocation_attempts : int = 0
56114
57115 @staticmethod
@@ -63,6 +121,58 @@ def new(input: StartDurableExecutionInput) -> Execution: # noqa: A002
63121 durable_execution_arn = str (uuid4 ()), start_input = input , operations = []
64122 )
65123
124+ def to_dict (self ) -> dict [str , Any ]:
125+ """Serialize execution to dictionary."""
126+ return {
127+ "DurableExecutionArn" : self .durable_execution_arn ,
128+ "StartInput" : self .start_input .to_dict (),
129+ "Operations" : [op .to_dict () for op in self .operations ],
130+ "Updates" : [update .to_dict () for update in self .updates ],
131+ "UsedTokens" : list (self .used_tokens ),
132+ "TokenSequence" : self .token_sequence ,
133+ "IsComplete" : self .is_complete ,
134+ "Result" : self .result .to_dict () if self .result else None ,
135+ "ConsecutiveFailedInvocationAttempts" : self .consecutive_failed_invocation_attempts ,
136+ }
137+
138+ @classmethod
139+ def from_dict (cls , data : dict [str , Any ]) -> Execution :
140+ """Deserialize execution from dictionary."""
141+ from aws_durable_execution_sdk_python_testing .model import (
142+ StartDurableExecutionInput ,
143+ )
144+
145+ # Reconstruct start_input
146+ start_input = StartDurableExecutionInput .from_dict (data ["StartInput" ])
147+
148+ # Reconstruct operations
149+ operations = [Operation .from_dict (op_data ) for op_data in data ["Operations" ]]
150+
151+ # Create execution
152+ execution = cls (
153+ durable_execution_arn = data ["DurableExecutionArn" ],
154+ start_input = start_input ,
155+ operations = operations ,
156+ )
157+
158+ # Set additional fields
159+ execution .updates = [
160+ _operation_update_from_dict (update_data ) for update_data in data ["Updates" ]
161+ ]
162+ execution .used_tokens = set (data ["UsedTokens" ])
163+ execution .token_sequence = data ["TokenSequence" ]
164+ execution .is_complete = data ["IsComplete" ]
165+ execution .result = (
166+ DurableExecutionInvocationOutput .from_dict (data ["Result" ])
167+ if data ["Result" ]
168+ else None
169+ )
170+ execution .consecutive_failed_invocation_attempts = data [
171+ "ConsecutiveFailedInvocationAttempts"
172+ ]
173+
174+ return execution
175+
66176 def start (self ) -> None :
67177 # not thread safe, prob should be
68178 if self .start_input .invocation_id is None :
0 commit comments