Dynamic backoff on DDos errors

This commit is contained in:
Matthias 2020-06-28 16:18:39 +02:00
parent 29d3ff1bc9
commit e040c518ca
2 changed files with 22 additions and 3 deletions

View File

@ -91,6 +91,13 @@ MAP_EXCHANGE_CHILDCLASS = {
} }
def calculate_backoff(retry, max_retries):
"""
Calculate backoff
"""
return retry ** 2 + 1
def retrier_async(f): def retrier_async(f):
async def wrapper(*args, **kwargs): async def wrapper(*args, **kwargs):
count = kwargs.pop('count', API_RETRY_COUNT) count = kwargs.pop('count', API_RETRY_COUNT)
@ -125,13 +132,13 @@ def retrier(_func=None, retries=API_RETRY_COUNT):
kwargs.update({'count': count}) kwargs.update({'count': count})
logger.warning('retrying %s() still for %s times', f.__name__, count) logger.warning('retrying %s() still for %s times', f.__name__, count)
if isinstance(ex, DDosProtection): if isinstance(ex, DDosProtection):
time.sleep(1) time.sleep(calculate_backoff(count, retries))
return wrapper(*args, **kwargs) return wrapper(*args, **kwargs)
else: else:
logger.warning('Giving up retrying: %s()', f.__name__) logger.warning('Giving up retrying: %s()', f.__name__)
raise ex raise ex
return wrapper return wrapper
# Support both @retrier and @retrier() syntax # Support both @retrier and @retrier(retries=2) syntax
if _func is None: if _func is None:
return decorator return decorator
else: else:

View File

@ -14,7 +14,7 @@ from pandas import DataFrame
from freqtrade.exceptions import (DependencyException, InvalidOrderException, DDosProtection, from freqtrade.exceptions import (DependencyException, InvalidOrderException, DDosProtection,
OperationalException, TemporaryError) OperationalException, TemporaryError)
from freqtrade.exchange import Binance, Exchange, Kraken from freqtrade.exchange import Binance, Exchange, Kraken
from freqtrade.exchange.common import API_RETRY_COUNT from freqtrade.exchange.common import API_RETRY_COUNT, calculate_backoff
from freqtrade.exchange.exchange import (market_is_active, symbol_is_pair, from freqtrade.exchange.exchange import (market_is_active, symbol_is_pair,
timeframe_to_minutes, timeframe_to_minutes,
timeframe_to_msecs, timeframe_to_msecs,
@ -2296,3 +2296,15 @@ def test_calculate_fee_rate(mocker, default_conf, order, expected) -> None:
ex = get_patched_exchange(mocker, default_conf) ex = get_patched_exchange(mocker, default_conf)
assert ex.calculate_fee_rate(order) == expected assert ex.calculate_fee_rate(order) == expected
@pytest.mark.parametrize('retry,max_retries,expected', [
(0, 3, 1),
(1, 3, 2),
(2, 3, 5),
(3, 3, 10),
(0, 1, 1),
(1, 1, 2),
])
def test_calculate_backoff(retry, max_retries, expected):
assert calculate_backoff(retry, max_retries) == expected