-
Notifications
You must be signed in to change notification settings - Fork 12
Description
Expected Behavior
The attempts_made parameter passed to the wait_strategy function should represent the current attempt being executed, starting at 1 and incrementing monotonically:
Execution 1: attempts_made = 1
Execution 2: attempts_made = 2
Execution 3: attempts_made = 3
Execution 4: attempts_made = 4
Execution 5: attempts_made = 5
This matches the JavaScript SDK behavior where:
const currentAttempt = (stepData?.StepDetails?.Attempt ?? 0) + 1;Reference:
- Step https://github.com/aws/aws-durable-execution-sdk-js/blob/main/packages/aws-durable-execution-sdk-js/src/handlers/step-handler/step-handler.ts#L158
- WaitForCondition https://github.com/aws/aws-durable-execution-sdk-js/blob/main/packages/aws-durable-execution-sdk-js/src/handlers/wait-for-condition-handler/wait-for-condition-handler.ts#L176
Actual Behavior
The attempts_made parameter incorrectly reports:
Execution 1: attempts_made = 1 ✓ (correct)
Execution 2: attempts_made = 1 ✗ (WRONG - should be 2)
Execution 3: attempts_made = 2 ✗ (WRONG - should be 3)
Execution 4: attempts_made = 3 ✗ (WRONG - should be 4)
Execution 5: attempts_made = 4 ✗ (WRONG - should be 5)
The first attempt is counted twice, causing all subsequent attempts to be off by one.
Steps to Reproduce
import random
from aws_durable_execution_sdk_python import DurableContext, durable_execution
from aws_durable_execution_sdk_python.config import Duration
from aws_durable_execution_sdk_python.waits import WaitForConditionConfig, WaitForConditionDecision
@durable_execution
def lambda_handler(event: dict, context: DurableContext) -> dict:
def check_status(status, context):
context.logger.info(f"check_status called with status: {status}")
if random.random() < 0.80:
status = "complete"
else:
status = "incomplete"
return {"status": status}
def wait_strategy(result, attempts_made: int) -> WaitForConditionDecision:
context.logger.info(f"wait_strategy called with attempts_made: {attempts_made}")
# Check if we've exceeded max attempts (5 iterations)
if attempts_made >= 5:
return WaitForConditionDecision.stop_polling()
# For the first attempt, delay by 10 seconds
if attempts_made == 1:
delay = Duration.from_seconds(10)
elif result["status"] == "complete":
return WaitForConditionDecision.stop_polling()
else:
# For subsequent attempts, delay by 2 seconds
delay = Duration.from_seconds(2)
return WaitForConditionDecision.continue_waiting(delay)
result = context.wait_for_condition(
name="poll",
check=check_status,
config=WaitForConditionConfig(
initial_state={"status":"incomplete"},
wait_strategy=wait_strategy
)
)
return resultSDK Version
1.1.1
Python Version
3.14
Is this a regression?
No
Last Working Version
No response
Additional Context
Root Cause
In src/aws_durable_execution_sdk_python/operation/wait_for_condition.py lines 157-159:
# Get attempt number
attempt: int = 1
if checkpointed_result.operation and checkpointed_result.operation.step_details:
attempt = checkpointed_result.operation.step_details.attemptThe code reads step_details.attempt directly, but this value represents how many attempts have been checkpointed (completed attempts), not what the current attempt is.
The semantic meaning:
step_details.attempt = 0→ No attempts checkpointed yet → Current attempt should be 1step_details.attempt = 1→ One attempt checkpointed → Current attempt should be 2step_details.attempt = N→ N attempts checkpointed → Current attempt should be N+1
Suggested Fix
Add 1 to the checkpointed attempt count to get the current attempt number:
# Get attempt number - current attempt is checkpointed attempts + 1
attempt: int = 1
if checkpointed_result.operation and checkpointed_result.operation.step_details:
attempt = checkpointed_result.operation.step_details.attempt + 1This matches the JavaScript SDK implementation:
// TypeScript wait-for-condition-handler.ts line 176
const currentAttempt = (stepData?.StepDetails?.Attempt ?? 0) + 1;