Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ jobs:
run: pytest -vv ${{ matrix.tests_config.params }}
env:
FORCE_RUN_DOCKER_TEST: ${{ matrix.tests_config.name == 'durable-functions' && '1' || '' }}
DURABLE_EXECUTIONS_EMULATOR_IMAGE_TAG: ${{ matrix.tests_config.name == 'durable-functions' && 'v1.1.1' || '' }}

smoke-and-functional-tests:
name: ${{ matrix.tests_config.name }} / ${{ matrix.tests_config.os }} / ${{ matrix.python }}
Expand Down
7 changes: 2 additions & 5 deletions tests/integration/local/invoke/test_invoke_durable.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,8 @@ def test_local_invoke_durable_function_timeout(self):
example = DurableFunctionExamples.EXECUTION_TIMEOUT
function_name = example.function_name
execution_name = "executiontimeout-integration-test"
event_path = str(self.test_data_path / "durable" / "events" / "timeout_test_event.json")

command_list = self.get_invoke_command_list(
function_name, event_path=event_path, durable_execution_name=execution_name
)
command_list = self.get_invoke_command_list(function_name, no_event=True, durable_execution_name=execution_name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding 3 of 3: the -e <event_path> code path for durable invokes is no longer exercised by the timeout test.

It's still covered by test_local_invoke_callback_heartbeat (line 181) which uses event_path=..., so it's not a total loss — flagging mainly because the timeout flow was the test most likely to fail on a regression in event-file handling specific to durable invoke (e.g., payload encoding, file read path differences when DurableExecutionName is also set). Worth a sanity check that the heartbeat test would actually catch such a regression, since it doesn't assert on the event contents being honored either.

stdout, stderr, invoke_return_code = self.run_command_with_logging(
command_list, f"test_local_invoke_durable_function_{function_name}"
Expand All @@ -84,7 +81,7 @@ def test_local_invoke_durable_function_timeout(self):

# Assert invoke output shows timeout
execution_arn = self.assert_invoke_output(
stdout, input_data={"wait_seconds": 30}, execution_name=execution_name, expected_status="TIMED_OUT"
stdout, input_data={}, execution_name=execution_name, expected_status="TIMED_OUT"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding 2 of 3: this weakens the only durable invoke test that asserted a non-trivial input made it into the execution-history output.

Before: input_data={"wait_seconds": 30}assert_invoke_output validated the input shown in the execution actually matched what was passed in.

After: input_data={} — there's nothing to validate against, so this branch of assert_invoke_output is effectively a no-op for propagation. Combined with the switch to --no-event, the timeout assertion now passes solely because the hardcoded handler does what it does, regardless of whether the event channel works at all.

If the goal is just stabilization, that's fine, but please consider keeping at least one durable test that asserts the input round-trips correctly through invoke → handler → execution history.

)

# Get and verify execution history
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,16 @@ def wait_for_execution_status(self, execution_arn, expected_status, max_wait=30)
time.sleep(1)
return execution_response

def invoke_and_wait_for_callback(self, payload=None):
"""Helper to invoke WaitForCallback function and wait for callback to be pending.
def invoke_and_wait_for_callback(self, payload=None, function_name="WaitForCallback"):
"""Helper to invoke a wait_for_callback function and wait for callback to be pending.

Returns:
tuple: (execution_arn, callback_id)
"""
if payload:
response = self.lambda_client.invoke(
FunctionName="WaitForCallback", InvocationType="Event", Payload=payload
)
response = self.lambda_client.invoke(FunctionName=function_name, InvocationType="Event", Payload=payload)
else:
response = self.lambda_client.invoke(FunctionName="WaitForCallback", InvocationType="Event")
response = self.lambda_client.invoke(FunctionName=function_name, InvocationType="Event")

execution_arn = self.assert_durable_invoke_response(
response, DurableFunctionExamples.WAIT_FOR_CALLBACK, invocation_type="Event"
Expand Down Expand Up @@ -170,12 +168,10 @@ def test_local_start_lambda_invoke_timeout(self):
"""Test start-lambda with durable function execution timeout."""
example = DurableFunctionExamples.EXECUTION_TIMEOUT
execution_name = "executiontimeout-integration-test"
event_data = {"wait_seconds": 30}

response = self.lambda_client.invoke(
FunctionName=example.function_name,
DurableExecutionName=execution_name,
Payload=json.dumps(event_data).encode("utf-8"),
)

self.assertEqual(response.get("StatusCode"), 200)
Expand Down Expand Up @@ -250,10 +246,7 @@ def test_local_start_lambda_invoke_wait_for_callback_failure_http(self, name, er
@pytest.mark.timeout(timeout=300, method="thread")
def test_local_start_lambda_invoke_wait_for_callback_timeout(self):
"""Test start-lambda with wait_for_callback timeout (no callback sent)."""
# Set a short timeout so test doesn't take too long
event_payload = json.dumps({"timeout_seconds": 5, "heartbeat_timeout_seconds": 3})

execution_arn, callback_id = self.invoke_and_wait_for_callback(payload=event_payload)
execution_arn, callback_id = self.invoke_and_wait_for_callback(function_name="WaitForCallbackShortTimeout")

# Don't send any callback - let it timeout
execution_response = self.wait_for_execution_status(execution_arn, "FAILED", max_wait=15)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
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


@durable_execution
def handler(event: Any, context: DurableContext) -> str:
context.wait(Duration.from_seconds(30), name="custom_wait")
return "Wait with name completed"
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import logging
from typing import Any

from aws_durable_execution_sdk_python.config import WaitForCallbackConfig
from aws_durable_execution_sdk_python.context import (
DurableContext,
WaitForCallbackContext,
)
from aws_durable_execution_sdk_python.execution import durable_execution
from aws_durable_execution_sdk_python.config import Duration

logger = logging.getLogger()
logger.setLevel(logging.INFO)


def external_system_call(callback_id: str, _context: WaitForCallbackContext) -> None:
logger.info(f"Waiting for callback: {callback_id}")


@durable_execution
def handler(event: Any, context: DurableContext) -> str:
config = WaitForCallbackConfig(
timeout=Duration.from_seconds(5),
heartbeat_timeout=Duration.from_seconds(3),
)

result = context.wait_for_callback(
external_system_call, name="external_call", config=config
)

return f"External system result: {result}"
8 changes: 7 additions & 1 deletion tests/integration/testdata/durable/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ Resources:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions
Handler: wait.wait_with_name.handler
Handler: wait.wait_30_seconds.handler
DurableConfig:
ExecutionTimeout: 5
RetentionPeriodInDays: 7

WaitForCallbackShortTimeout:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions
Handler: wait_for_callback.wait_for_callback_short_timeout.handler
Loading