@@ -2080,6 +2080,42 @@ def _workflow_sequence(payload: Mapping[str, Any]) -> int | None:
20802080 return None
20812081
20822082
2083+ def _internal_timeout_timer_kind (
2084+ payload : Mapping [str , Any ],
2085+ condition_wait_ids_by_sequence : Mapping [int , str ] | None = None ,
2086+ ) -> str | None :
2087+ """Identify internal wait timers without adding them to the command cursor."""
2088+ timer_kind = payload .get ("timer_kind" )
2089+ if timer_kind in ("condition_timeout" , "signal_timeout" ):
2090+ return str (timer_kind )
2091+ if _optional_str (payload .get ("condition_wait_id" )) is not None :
2092+ return "condition_timeout"
2093+ if _optional_str (payload .get ("signal_wait_id" )) is not None :
2094+ return "signal_timeout"
2095+
2096+ sequence = _workflow_sequence (payload )
2097+ if (
2098+ sequence is not None
2099+ and condition_wait_ids_by_sequence is not None
2100+ and sequence in condition_wait_ids_by_sequence
2101+ ):
2102+ return "condition_timeout"
2103+ return None
2104+
2105+
2106+ def _condition_timeout_wait_id (
2107+ payload : Mapping [str , Any ],
2108+ condition_wait_ids_by_sequence : Mapping [int , str ],
2109+ ) -> str | None :
2110+ if _internal_timeout_timer_kind (payload , condition_wait_ids_by_sequence ) != "condition_timeout" :
2111+ return None
2112+ wait_id = _optional_str (payload .get ("condition_wait_id" ))
2113+ if wait_id is not None :
2114+ return wait_id
2115+ sequence = _workflow_sequence (payload )
2116+ return condition_wait_ids_by_sequence .get (sequence ) if sequence is not None else None
2117+
2118+
20832119def _activity_type_from_payload (payload : Mapping [str , Any ]) -> str | None :
20842120 activity_type = _optional_str (payload .get ("activity_type" ))
20852121 if activity_type is not None :
@@ -2121,7 +2157,11 @@ def _recorded_step_details(payload: Mapping[str, Any]) -> dict[str, Any]:
21212157 return details
21222158
21232159
2124- def _is_resolved_step_event (event_type : str | None , payload : Mapping [str , Any ]) -> bool :
2160+ def _is_resolved_step_event (
2161+ event_type : str | None ,
2162+ payload : Mapping [str , Any ],
2163+ condition_wait_ids_by_sequence : Mapping [int , str ] | None = None ,
2164+ ) -> bool :
21252165 if event_type in (
21262166 "ActivityCompleted" ,
21272167 "ActivityFailed" ,
@@ -2136,7 +2176,7 @@ def _is_resolved_step_event(event_type: str | None, payload: Mapping[str, Any])
21362176 ):
21372177 return True
21382178 if event_type == "TimerFired" :
2139- return payload . get ( "timer_kind" ) not in ( "condition_timeout" , "signal_timeout" )
2179+ return _internal_timeout_timer_kind ( payload , condition_wait_ids_by_sequence ) is None
21402180 return False
21412181
21422182
@@ -2347,13 +2387,24 @@ def _replay_state(
23472387 if event_type is not None :
23482388 event_types_by_sequence .setdefault (sequence , []).append (event_type )
23492389 details_by_sequence .setdefault (sequence , {}).update (_recorded_step_details (payload ))
2350- if _is_resolved_step_event (event_type , payload ):
2351- resolved_sequences .add (sequence )
23522390 if event_type == "ConditionWaitOpened" :
23532391 wait_id = payload .get ("condition_wait_id" )
23542392 if isinstance (wait_id , str ) and wait_id :
23552393 condition_wait_ids_by_sequence [sequence ] = wait_id
23562394
2395+ for event in events :
2396+ event_type = _history_event_type (event )
2397+ payload = event .get ("payload" ) or {}
2398+ if not isinstance (payload , Mapping ):
2399+ payload = {}
2400+ sequence = _workflow_sequence (payload )
2401+ if sequence is not None and _is_resolved_step_event (
2402+ event_type ,
2403+ payload ,
2404+ condition_wait_ids_by_sequence ,
2405+ ):
2406+ resolved_sequences .add (sequence )
2407+
23572408 workflow_start_time : datetime | None = None
23582409 for ev in events :
23592410 etype = _history_event_type (ev )
@@ -2395,6 +2446,7 @@ def _state(commands: list[Command]) -> _ReplayState:
23952446 # in history, future server-recorded) or 'timed_out' (from a matching
23962447 # condition_timeout TimerFired event).
23972448 wait_resolutions : dict [str , str ] = {}
2449+
23982450 def _append_resolved_result (value : Any , shape : str , event : Mapping [str , Any ]) -> None :
23992451 payload = event .get ("payload" ) or {}
24002452 if not isinstance (payload , Mapping ):
@@ -2519,7 +2571,11 @@ def _receiver_binding_boundary_kind(event_type: str | None, payload: Mapping[str
25192571 return "condition"
25202572 if (
25212573 event_type in ("TimerFired" , "TimerCancelled" )
2522- and payload .get ("timer_kind" ) == "condition_timeout"
2574+ and _internal_timeout_timer_kind (
2575+ payload ,
2576+ condition_wait_ids_by_sequence ,
2577+ )
2578+ == "condition_timeout"
25232579 ):
25242580 return "condition"
25252581 if event_type in (
@@ -2533,8 +2589,24 @@ def _receiver_binding_boundary_kind(event_type: str | None, payload: Mapping[str
25332589 ):
25342590 return "step"
25352591 if event_type == "TimerScheduled" :
2536- return "step" if payload .get ("timer_kind" ) not in ("condition_timeout" , "signal_timeout" ) else None
2537- return "step" if _is_resolved_step_event (event_type , payload ) else None
2592+ return (
2593+ "step"
2594+ if _internal_timeout_timer_kind (
2595+ payload ,
2596+ condition_wait_ids_by_sequence ,
2597+ )
2598+ is None
2599+ else None
2600+ )
2601+ return (
2602+ "step"
2603+ if _is_resolved_step_event (
2604+ event_type ,
2605+ payload ,
2606+ condition_wait_ids_by_sequence ,
2607+ )
2608+ else None
2609+ )
25382610
25392611 def _receiver_condition_wait_bindings () -> dict [int , str | None ]:
25402612 bindings : dict [int , str | None ] = {}
@@ -2635,18 +2707,27 @@ def _receiver_condition_wait_bindings() -> dict[int, str | None]:
26352707 elif etype in ("ActivityScheduled" , "ActivityStarted" ):
26362708 _append_pending_step ("activity" , ev )
26372709 elif etype == "TimerFired" :
2638- timer_kind = payload .get ("timer_kind" )
2710+ timer_kind = _internal_timeout_timer_kind (
2711+ payload ,
2712+ condition_wait_ids_by_sequence ,
2713+ )
26392714 if timer_kind == "condition_timeout" :
2640- wait_id = payload .get ("condition_wait_id" )
2641- if isinstance (wait_id , str ) and wait_id :
2715+ wait_id = _condition_timeout_wait_id (
2716+ payload ,
2717+ condition_wait_ids_by_sequence ,
2718+ )
2719+ if wait_id is not None :
26422720 wait_resolutions [wait_id ] = "timed_out"
26432721 continue
26442722 if timer_kind == "signal_timeout" :
26452723 continue
26462724 _append_resolved_result (None , "timer" , ev )
26472725 elif etype == "TimerScheduled" :
2648- timer_kind = payload .get ("timer_kind" )
2649- if timer_kind not in ("condition_timeout" , "signal_timeout" ):
2726+ timer_kind = _internal_timeout_timer_kind (
2727+ payload ,
2728+ condition_wait_ids_by_sequence ,
2729+ )
2730+ if timer_kind is None :
26502731 _append_pending_step ("timer" , ev )
26512732 elif etype == "ConditionWaitOpened" :
26522733 wait_id = payload .get ("condition_wait_id" )
@@ -3054,12 +3135,12 @@ def _terminal_state(value: Any, *, include_pending: bool) -> _ReplayState:
30543135 wait_yield_count = next_wait_index
30553136 return _state (pending )
30563137 continue
3057- if isinstance (cmd , ( ScheduleActivity , StartTimer , StartChildWorkflow ) ):
3138+ if isinstance (cmd , ScheduleActivity | StartTimer | StartChildWorkflow ):
30583139 if result_cursor < len (resolved_results ):
30593140 _assert_next_step_matches (cmd )
30603141 val = resolved_results [result_cursor ]
30613142 result_cursor += 1
3062- if isinstance (val , ( ActivityFailed , ChildWorkflowFailed ) ):
3143+ if isinstance (val , ActivityFailed | ChildWorkflowFailed ):
30633144 try :
30643145 advanced_cmd = gen .throw (val )
30653146 continue
0 commit comments