Skip to content

feat: with retry helper#390

Open
wangyb-A wants to merge 1 commit into
mainfrom
feat/withRetry
Open

feat: with retry helper#390
wangyb-A wants to merge 1 commit into
mainfrom
feat/withRetry

Conversation

@wangyb-A
Copy link
Copy Markdown
Contributor

@wangyb-A wangyb-A commented May 12, 2026

Issue #, if available: #361

Ref pr: aws/aws-durable-execution-sdk-js#505

Description

  • Runs func(ctx, attempt) starting at attempt = 1.
  • On rejection → calls retryStrategy. If shouldRetry: true, context.waits for the returned delay, then re-runs the whole function.
  • On fulfillment → returns the value.
  • On the final failure → rethrows.
  • By default wraps the loop in context.runInChildContext for isolation and so all attempts + backoff waits appear as a single grouped operation in execution history. Opt out via wrap_with_run_in_child_context = false
iShot_2026-05-12_15 00 33

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@wangyb-A wangyb-A marked this pull request as ready for review May 12, 2026 22:37
@yaythomas yaythomas moved this from Backlog to In review in aws-durable-execution May 20, 2026
@wangyb-A wangyb-A self-assigned this May 20, 2026


@dataclass(frozen=True)
class WithRetryConfig:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WithRetryConfig<T> will let the type flow to ChildConfig[T] | None.

ChildConfig is already Generic[T].

Comment thread tests/with_retry_test.py
max_attempts=4,
initial_delay=Duration.from_seconds(2),
backoff_rate=2.0,
jitter_strategy=__import__(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

avoid inline imports, pls.

Comment thread tests/with_retry_test.py
retry_strategy_config=RetryStrategyConfig(
max_attempts=3,
initial_delay=Duration.from_seconds(1),
jitter_strategy=__import__(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

avoid inline imports, pls.

Comment thread tests/with_retry_test.py
child_context_config: ChildConfig | None = None,
) -> WithRetryConfig:
"""Create a WithRetryConfig with no jitter for deterministic tests."""
from aws_durable_execution_sdk_python.config import JitterStrategy
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

avoid inline imports, pls

Comment thread tests/with_retry_test.py
config = _make_config(wrap_with_run_in_child_context=False)

strategy_calls: list = []
original_create = create_retry_strategy
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

these aren't used?

Comment thread tests/with_retry_test.py


def test_success_on_first_attempt_returns_result_without_retry_strategy():
"""Function succeeds on first attempt returns result without invoking retry strategy."""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

name is a little misleading, since a retry strategy is configured, the test asserts it wasn't invoked

behavior (max_attempts, initial_delay, backoff_rate, jitter,
error filtering). The same config used for step retries.
wrap_with_run_in_child_context: Whether to wrap the retry loop in
a child context for isolation. Default True.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

could be helpful to add:

  • default True: final failure rethrown as CallableRuntimeError, original on cause
  • False: original error rethrown unchanged

Returns:
The result of func on successful execution.

Raises:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe also document when the wrapped child fails, ChildOperationExecutor.process wraps
non-InvocationError/SuspendExecution exceptions as CallableRuntimeError, with the original error in cause via raise … from e. When wrap_with_run_in_child_context=False, the original exception propagates unchanged.

@@ -0,0 +1,65 @@
"""Demonstrates with_retry wrapping a wait_for_callback operation.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not registered in examples/examples-catalog.json?

wrap_with_run_in_child_context is False.
"""

retry_strategy_config: RetryStrategyConfig
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What is this instead is Callable[[Exception, int], RetryDecision] | None, so:

config = WithRetryConfig(
    retry_strategy=create_retry_strategy(RetryStrategyConfig(
        max_attempts=5,
        initial_delay=Duration.from_seconds(2),
        backoff_rate=1.0,
    )),
)

This follows the same sort of pattern as StepConfig.retry_strategy

@github-project-automation github-project-automation Bot moved this from In review to In progress in aws-durable-execution May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

2 participants