Skip to content

Commit efcbca0

Browse files
committed
fix: remove timeout from Invoke Config (v2 breaking change)
1 parent 272c1f4 commit efcbca0

5 files changed

Lines changed: 18 additions & 90 deletions

File tree

packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/config.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -479,13 +479,9 @@ class InvokeConfig(Generic[P, R]):
479479
Configuration for invoke operations.
480480
481481
This class configures how function invocations are executed, including
482-
timeout behavior, serialization, and tenant isolation.
482+
serialization and tenant isolation.
483483
484484
Args:
485-
timeout: Maximum duration to wait for the invoked function to complete.
486-
Default is no timeout. Use this to prevent long-running invocations
487-
from blocking execution indefinitely.
488-
489485
serdes_payload: Custom serialization/deserialization for the payload
490486
sent to the invoked function. Defaults to DEFAULT_JSON_SERDES when
491487
not set.
@@ -499,16 +495,10 @@ class InvokeConfig(Generic[P, R]):
499495
"""
500496

501497
# retry_strategy: Callable[[Exception, int], RetryDecision] | None = None
502-
timeout: Duration = field(default_factory=Duration)
503498
serdes_payload: SerDes[P] | None = None
504499
serdes_result: SerDes[R] | None = None
505500
tenant_id: str | None = None
506501

507-
@property
508-
def timeout_seconds(self) -> int:
509-
"""Get timeout in seconds."""
510-
return self.timeout.to_seconds()
511-
512502

513503
@dataclass(frozen=True)
514504
class CallbackConfig:

packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/invoke.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def execute(self, _checkpointed_result: CheckpointedResult) -> R:
166166
ExecutionError: If suspend doesn't raise (should never happen)
167167
"""
168168
msg: str = f"Invoke {self.operation_identifier.operation_id} started, suspending for completion"
169-
suspend_with_optional_resume_delay(msg, self.config.timeout_seconds)
169+
suspend_with_optional_resume_delay(msg)
170170
# This line should never be reached since suspend_with_optional_resume_delay always raises
171171
error_msg: str = "suspend_with_optional_resume_delay should have raised an exception, but did not."
172172
raise ExecutionError(error_msg) from None

packages/aws-durable-execution-sdk-python/tests/config_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,6 @@ def test_invoke_config_defaults():
271271
"""Test InvokeConfig defaults."""
272272
config = InvokeConfig()
273273
assert config.tenant_id is None
274-
assert config.timeout_seconds == 0
275274

276275

277276
def test_invoke_config_with_tenant_id():

packages/aws-durable-execution-sdk-python/tests/context_test.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ def test_invoke_with_name_and_config(mock_executor_class):
644644
mock_state.durable_execution_arn = (
645645
"arn:aws:durable:us-east-1:123456789012:execution/test"
646646
)
647-
config = InvokeConfig[str, str](timeout=Duration.from_seconds(30))
647+
config = InvokeConfig[str, str]()
648648

649649
context = create_test_context(state=mock_state)
650650
[context._create_step_id() for _ in range(5)] # Set counter to 5 # noqa: SLF001
@@ -790,7 +790,6 @@ def test_invoke_with_custom_serdes(mock_executor_class):
790790
config = InvokeConfig[dict, dict](
791791
serdes_payload=payload_serdes,
792792
serdes_result=result_serdes,
793-
timeout=Duration.from_minutes(1),
794793
)
795794

796795
context = create_test_context(state=mock_state)

packages/aws-durable-execution-sdk-python/tests/operation/invoke_test.py

Lines changed: 15 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import pytest
99

10-
from aws_durable_execution_sdk_python.config import Duration, InvokeConfig
10+
from aws_durable_execution_sdk_python.config import InvokeConfig
1111
from aws_durable_execution_sdk_python.exceptions import (
1212
CallableRuntimeError,
1313
ExecutionError,
@@ -218,8 +218,8 @@ def test_invoke_handler_already_started(status):
218218

219219

220220
@pytest.mark.parametrize("status", [OperationStatus.STARTED, OperationStatus.PENDING])
221-
def test_invoke_handler_already_started_with_timeout(status):
222-
"""Test invoke_handler when operation is already started with timeout config."""
221+
def test_invoke_handler_already_started_suspends(status):
222+
"""Test invoke_handler when operation is already started suspends indefinitely."""
223223
mock_state = Mock(spec=ExecutionState)
224224
mock_state.durable_execution_arn = "test_arn"
225225

@@ -232,9 +232,9 @@ def test_invoke_handler_already_started_with_timeout(status):
232232
mock_result = CheckpointedResult.create_from_operation(operation)
233233
mock_state.get_checkpoint_result.return_value = mock_result
234234

235-
config = InvokeConfig[str, str](timeout=Duration.from_seconds(30))
235+
config = InvokeConfig[str, str]()
236236

237-
with pytest.raises(TimedSuspendExecution):
237+
with pytest.raises(SuspendExecution):
238238
invoke_handler(
239239
function_name="test_function",
240240
payload="test_input",
@@ -261,7 +261,7 @@ def test_invoke_handler_new_operation():
261261
started = CheckpointedResult.create_from_operation(started_op)
262262
mock_state.get_checkpoint_result.side_effect = [not_found, started]
263263

264-
config = InvokeConfig[str, str](timeout=Duration.from_minutes(1))
264+
config = InvokeConfig[str, str]()
265265

266266
with pytest.raises(
267267
SuspendExecution, match="Invoke invoke8 started, suspending for completion"
@@ -288,62 +288,6 @@ def test_invoke_handler_new_operation():
288288
assert operation_update.chained_invoke_options.function_name == "test_function"
289289

290290

291-
def test_invoke_handler_new_operation_with_timeout():
292-
"""Test invoke_handler when starting a new operation with timeout."""
293-
mock_state = Mock(spec=ExecutionState)
294-
mock_state.durable_execution_arn = "test_arn"
295-
296-
not_found = CheckpointedResult.create_not_found()
297-
started_op = Operation(
298-
operation_id="invoke_test",
299-
operation_type=OperationType.CHAINED_INVOKE,
300-
status=OperationStatus.STARTED,
301-
)
302-
started = CheckpointedResult.create_from_operation(started_op)
303-
mock_state.get_checkpoint_result.side_effect = [not_found, started]
304-
305-
config = InvokeConfig[str, str](timeout=Duration.from_seconds(30))
306-
307-
with pytest.raises(TimedSuspendExecution):
308-
invoke_handler(
309-
function_name="test_function",
310-
payload="test_input",
311-
state=mock_state,
312-
operation_identifier=OperationIdentifier(
313-
"invoke9", OperationSubType.CHAINED_INVOKE, None, "test_invoke"
314-
),
315-
config=config,
316-
)
317-
318-
319-
def test_invoke_handler_new_operation_no_timeout():
320-
"""Test invoke_handler when starting a new operation without timeout."""
321-
mock_state = Mock(spec=ExecutionState)
322-
mock_state.durable_execution_arn = "test_arn"
323-
324-
not_found = CheckpointedResult.create_not_found()
325-
started_op = Operation(
326-
operation_id="invoke_test",
327-
operation_type=OperationType.CHAINED_INVOKE,
328-
status=OperationStatus.STARTED,
329-
)
330-
started = CheckpointedResult.create_from_operation(started_op)
331-
mock_state.get_checkpoint_result.side_effect = [not_found, started]
332-
333-
config = InvokeConfig[str, str](timeout=Duration.from_seconds(0))
334-
335-
with pytest.raises(SuspendExecution):
336-
invoke_handler(
337-
function_name="test_function",
338-
payload="test_input",
339-
state=mock_state,
340-
operation_identifier=OperationIdentifier(
341-
"invoke10", OperationSubType.CHAINED_INVOKE, None, "test_invoke"
342-
),
343-
config=config,
344-
)
345-
346-
347291
def test_invoke_handler_no_config():
348292
"""Test invoke_handler when no config is provided."""
349293
mock_state = Mock(spec=ExecutionState)
@@ -1067,8 +1011,8 @@ def test_invoke_immediate_response_already_completed():
10671011
assert mock_state.get_checkpoint_result.call_count == 1
10681012

10691013

1070-
def test_invoke_immediate_response_with_timeout_immediate_success():
1071-
"""Test immediate success with timeout configuration."""
1014+
def test_invoke_immediate_response_immediate_success():
1015+
"""Test immediate success response."""
10721016
mock_state = Mock(spec=ExecutionState)
10731017
mock_state.durable_execution_arn = "test_arn"
10741018

@@ -1079,13 +1023,13 @@ def test_invoke_immediate_response_with_timeout_immediate_success():
10791023
operation_type=OperationType.CHAINED_INVOKE,
10801024
status=OperationStatus.SUCCEEDED,
10811025
chained_invoke_details=ChainedInvokeDetails(
1082-
result=json.dumps("timeout_result")
1026+
result=json.dumps("immediate_result")
10831027
),
10841028
)
10851029
succeeded = CheckpointedResult.create_from_operation(succeeded_op)
10861030
mock_state.get_checkpoint_result.side_effect = [not_found, succeeded]
10871031

1088-
config = InvokeConfig[str, str](timeout=Duration.from_seconds(30))
1032+
config = InvokeConfig[str, str]()
10891033

10901034
result = invoke_handler(
10911035
function_name="test_function",
@@ -1098,15 +1042,12 @@ def test_invoke_immediate_response_with_timeout_immediate_success():
10981042
)
10991043

11001044
# Verify result was returned without suspend
1101-
assert result == "timeout_result"
1045+
assert result == "immediate_result"
11021046
assert mock_state.get_checkpoint_result.call_count == 2
11031047

11041048

1105-
def test_invoke_immediate_response_with_timeout_no_immediate_response():
1106-
"""Test no immediate response with timeout configuration.
1107-
1108-
When no immediate response, operation should suspend with timeout.
1109-
"""
1049+
def test_invoke_immediate_response_no_immediate_response():
1050+
"""Test no immediate response — operation suspends indefinitely."""
11101051
mock_state = Mock(spec=ExecutionState)
11111052
mock_state.durable_execution_arn = "test_arn"
11121053

@@ -1120,10 +1061,9 @@ def test_invoke_immediate_response_with_timeout_no_immediate_response():
11201061
started = CheckpointedResult.create_from_operation(started_op)
11211062
mock_state.get_checkpoint_result.side_effect = [not_found, started]
11221063

1123-
config = InvokeConfig[str, str](timeout=Duration.from_seconds(30))
1064+
config = InvokeConfig[str, str]()
11241065

1125-
# Verify operation suspends with timeout
1126-
with pytest.raises(TimedSuspendExecution):
1066+
with pytest.raises(SuspendExecution):
11271067
invoke_handler(
11281068
function_name="test_function",
11291069
payload="test_input",

0 commit comments

Comments
 (0)