-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add exponential backoff retry to transaction retry decorator (#37)
* Add exponential backoff retry to transaction retry decorator * Added arguments `retries` and `backoff_factor` to `retry_transaction` decorator. * Update pylint dependency to resolve crash during ci * Use namekos retry decorator for transaction retry * Revert back to own implementation of retry - Use behavior and api (backoff argument names) from urllib3 retry - Add explanation of backoff algorithm to README - Fix incorrect test comments
- Loading branch information
1 parent
9871e33
commit da82b64
Showing
5 changed files
with
193 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,65 @@ | ||
from time import sleep | ||
import functools | ||
import operator | ||
|
||
import wrapt | ||
from sqlalchemy import exc | ||
|
||
|
||
def transaction_retry(wrapped=None, session=None): | ||
def transaction_retry(wrapped=None, session=None, total=1, | ||
backoff_factor=0, backoff_max=None): | ||
|
||
if wrapped is None: | ||
return functools.partial(transaction_retry, session=session) | ||
return functools.partial( | ||
transaction_retry, session=session, | ||
total=total, | ||
backoff_factor=backoff_factor, | ||
backoff_max=backoff_max) | ||
|
||
@wrapt.decorator | ||
def wrapper(wrapped, instance, args, kwargs): | ||
|
||
try: | ||
return wrapped(*args, **kwargs) | ||
except exc.OperationalError as exception: | ||
if exception.connection_invalidated: | ||
if isinstance(session, operator.attrgetter): | ||
session(instance).rollback() | ||
elif session: | ||
session.rollback() | ||
@retry(total, backoff_factor, backoff_max, exc.OperationalError) | ||
def run_or_rollback(): | ||
try: | ||
return wrapped(*args, **kwargs) | ||
else: | ||
except exc.OperationalError as exception: | ||
if exception.connection_invalidated: | ||
if isinstance(session, operator.attrgetter): | ||
session(instance).rollback() | ||
elif session: | ||
session.rollback() | ||
raise | ||
|
||
return run_or_rollback() | ||
|
||
return wrapper(wrapped) # pylint: disable=E1120 | ||
|
||
|
||
def retry(total, backoff_factor, backoff_max, exceptions): | ||
|
||
total = max(total, 1) | ||
backoff_factor = max(backoff_factor, 0) | ||
backoff_max = float('inf') if backoff_max is None else max(0, backoff_max) | ||
|
||
@wrapt.decorator | ||
def wrapper(wrapped, instance, args, kwargs): | ||
errors = 0 | ||
while True: | ||
try: | ||
return wrapped(*args, **kwargs) | ||
except exceptions: | ||
errors += 1 | ||
|
||
if errors > total: | ||
raise | ||
|
||
if errors >= 2: | ||
backoff_value = backoff_factor * (2 ** (errors - 1)) | ||
else: | ||
backoff_value = 0 | ||
backoff_value = min(backoff_value, backoff_max) | ||
|
||
sleep(backoff_value) | ||
|
||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters