From 62d6fedb764965836ef833d006d52c82fc1b3870 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 21 Jan 2026 11:36:09 +0000 Subject: [PATCH] fix: honor timed_out terminal state --- src/aws_durable_execution_sdk_python/state.py | 1 + tests/state_test.py | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/aws_durable_execution_sdk_python/state.py b/src/aws_durable_execution_sdk_python/state.py index 8553a7d..6bc6826 100644 --- a/src/aws_durable_execution_sdk_python/state.py +++ b/src/aws_durable_execution_sdk_python/state.py @@ -314,6 +314,7 @@ def track_replay(self, operation_id: str) -> None: OperationStatus.FAILED, OperationStatus.CANCELLED, OperationStatus.STOPPED, + OperationStatus.TIMED_OUT, } } if completed_ops.issubset(self._visited_operations): diff --git a/tests/state_test.py b/tests/state_test.py index d997abf..be9e6dd 100644 --- a/tests/state_test.py +++ b/tests/state_test.py @@ -3265,3 +3265,36 @@ def test_state_replay_mode(): assert execution_state.is_replaying() is True execution_state.track_replay(operation_id="op2") assert execution_state.is_replaying() is False + + +def test_state_replay_mode_with_timed_out(): + """Test that TIMED_OUT operations are treated as terminal states for replay tracking. + + This test verifies that when an operation has TIMED_OUT status, it is correctly + recognized as a completed/terminal state, allowing the replay status to transition + from REPLAY to NEW once all completed operations have been visited. + + Regression test for: https://github.com/aws/aws-durable-execution-sdk-python/issues/262 + """ + operation1 = Operation( + operation_id="op1", + operation_type=OperationType.STEP, + status=OperationStatus.TIMED_OUT, + ) + operation2 = Operation( + operation_id="op2", + operation_type=OperationType.STEP, + status=OperationStatus.SUCCEEDED, + ) + execution_state = ExecutionState( + durable_execution_arn="arn:aws:test", + initial_checkpoint_token="test_token", # noqa: S106 + operations={"op1": operation1, "op2": operation2}, + service_client=Mock(), + replay_status=ReplayStatus.REPLAY, + ) + assert execution_state.is_replaying() is True + execution_state.track_replay(operation_id="op1") + assert execution_state.is_replaying() is True + execution_state.track_replay(operation_id="op2") + assert execution_state.is_replaying() is False