-
Notifications
You must be signed in to change notification settings - Fork 24
Implement Retry Strategy Resolver Pattern with Per-Client Caching #600
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 8 commits
7e0ef1c
1b6c10c
2c14d20
829e742
73b527b
8cd4c92
7870054
ff2c368
dd748a8
572302e
24aa35b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,60 @@ | ||
| # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| import random | ||
| import threading | ||
| from collections.abc import Callable | ||
| from dataclasses import dataclass | ||
| from enum import Enum | ||
|
|
||
| from .exceptions import RetryError | ||
| from .interfaces import retries as retries_interface | ||
| from .interfaces.retries import RetryStrategy, RetryStrategyResolver, RetryStrategyType | ||
|
|
||
|
|
||
| @dataclass(kw_only=True, frozen=True) | ||
| class RetryStrategyOptions: | ||
| """Options for configuring retry behavior.""" | ||
|
|
||
| retry_mode: RetryStrategyType = "simple" | ||
| """The retry mode to use.""" | ||
|
|
||
| max_attempts: int = 3 | ||
| """Maximum number of attempts (initial attempt plus retries).""" | ||
|
|
||
|
|
||
| class CachingRetryStrategyResolver(RetryStrategyResolver[RetryStrategy]): | ||
| """Retry strategy resolver that caches retry strategies based on configuration options. | ||
| This resolver caches retry strategy instances based on their configuration to reuse existing | ||
| instances of RetryStrategy with the same settings. | ||
| """ | ||
|
|
||
| def __init__(self) -> None: | ||
| self._cache: dict[RetryStrategyOptions, RetryStrategy] = {} | ||
|
||
| self._lock = threading.Lock() | ||
|
|
||
| async def resolve_retry_strategy( | ||
| self, *, options: RetryStrategyOptions | ||
| ) -> RetryStrategy: | ||
| """Resolve a retry strategy from the provided options, using cache when possible. | ||
| :param options: The retry strategy options to use for creating the strategy. | ||
| """ | ||
| with self._lock: | ||
| if options not in self._cache: | ||
| self._cache[options] = self._create_retry_strategy( | ||
| options.retry_mode, options.max_attempts | ||
| ) | ||
| return self._cache[options] | ||
|
|
||
| def _create_retry_strategy( | ||
| self, retry_mode: RetryStrategyType, max_attempts: int | ||
| ) -> RetryStrategy: | ||
| match retry_mode: | ||
| case "simple": | ||
| return SimpleRetryStrategy(max_attempts=max_attempts) | ||
| case _: | ||
| raise ValueError(f"Unknown retry mode: {retry_mode}") | ||
|
|
||
|
|
||
| class ExponentialBackoffJitterType(Enum): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What other kinds of
RetryStrategyResolverare we envisioning? This seems like it only has one real use which is to create a RetryStrategy if one isn't provided.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a holdover from when customers could supply their own resolvers in an earlier revision of this PR.
When I considered removing it, I figured it may make sense to keep it as close as possible to other resolvers in the repo like the identity resolver, but in this instance it really doesn't serve any purpose so I've removed it.