diff --git a/examples/examples-catalog.json b/examples/examples-catalog.json index ae9a8de..9bc3014 100644 --- a/examples/examples-catalog.json +++ b/examples/examples-catalog.json @@ -188,6 +188,17 @@ }, "path": "./src/wait_for_callback/wait_for_callback_serdes.py" }, + { + "name": "Wait For Callback Timeout", + "description": "Usage of context.wait_for_callback() to wait for external system responses", + "handler": "wait_for_callback_timeout.handler", + "integration": true, + "durableConfig": { + "RetentionPeriodInDays": 7, + "ExecutionTimeout": 300 + }, + "path": "./src/wait_for_callback/wait_for_callback_timeout.py" + }, { "name": "Wait For Callback Nested", "description": "Usage of context.wait_for_callback() to wait for external system responses", diff --git a/examples/src/wait_for_callback/wait_for_callback_timeout.py b/examples/src/wait_for_callback/wait_for_callback_timeout.py new file mode 100644 index 0000000..0423dad --- /dev/null +++ b/examples/src/wait_for_callback/wait_for_callback_timeout.py @@ -0,0 +1,37 @@ +"""Demonstrates waitForCallback timeout scenarios.""" + +from typing import Any + +from aws_durable_execution_sdk_python.context import DurableContext +from aws_durable_execution_sdk_python.execution import durable_execution +from aws_durable_execution_sdk_python.config import Duration +from aws_durable_execution_sdk_python.config import WaitForCallbackConfig + + +@durable_execution +def handler(_event: Any, context: DurableContext) -> dict[str, Any]: + """Handler demonstrating waitForCallback timeout.""" + + config = WaitForCallbackConfig( + timeout=Duration.from_seconds(1), heartbeat_timeout=Duration.from_seconds(2) + ) + + def submitter(_) -> None: + """Submitter succeeds but callback never completes.""" + return None + + try: + result: str = context.wait_for_callback( + submitter, + config=config, + ) + + return { + "callbackResult": result, + "success": True, + } + except Exception as error: + return { + "success": False, + "error": str(error), + } diff --git a/examples/template.yaml b/examples/template.yaml index 67d4c29..b323cb5 100644 --- a/examples/template.yaml +++ b/examples/template.yaml @@ -254,6 +254,20 @@ Resources: DurableConfig: RetentionPeriodInDays: 7 ExecutionTimeout: 300 + WaitForCallbackTimeout: + Type: AWS::Serverless::Function + Properties: + CodeUri: build/ + Handler: wait_for_callback_timeout.handler + Description: Usage of context.wait_for_callback() to wait for external system + responses + Role: + Fn::GetAtt: + - DurableFunctionRole + - Arn + DurableConfig: + RetentionPeriodInDays: 7 + ExecutionTimeout: 300 WaitForCallbackNested: Type: AWS::Serverless::Function Properties: diff --git a/examples/test/wait_for_callback/test_wait_for_callback_timeout.py b/examples/test/wait_for_callback/test_wait_for_callback_timeout.py new file mode 100644 index 0000000..e330272 --- /dev/null +++ b/examples/test/wait_for_callback/test_wait_for_callback_timeout.py @@ -0,0 +1,32 @@ +"""Tests for wait_for_callback_timeout.""" + +import pytest +from aws_durable_execution_sdk_python.execution import InvocationStatus + +from src.wait_for_callback import wait_for_callback_timeout +from test.conftest import deserialize_operation_payload + + +@pytest.mark.example +@pytest.mark.durable_execution( + handler=wait_for_callback_timeout.handler, + lambda_function_name="Wait For Callback Timeout", +) +def test_handle_wait_for_callback_timeout_scenarios(durable_runner): + """Test waitForCallback timeout scenarios.""" + test_payload = {"test": "timeout-scenario"} + + with durable_runner: + execution_arn = durable_runner.run_async(input=test_payload, timeout=30) + # Don't send callback - let it timeout + result = durable_runner.wait_for_result(execution_arn=execution_arn) + + # Handler catches the timeout error, so execution succeeds with error in result + assert result.status is InvocationStatus.SUCCEEDED + + result_data = deserialize_operation_payload(result.result) + + assert result_data["success"] is False + assert isinstance(result_data["error"], str) + assert len(result_data["error"]) > 0 + assert "Callback timed out" == result_data["error"]