Browse Source

Replace retrying with tenacity

We are replacing all usages of the 'retrying' package with
'tenacity' as the author of retrying is not actively maintaining
the project. Tenacity is a fork of retrying, but has improved the
interface and extensibility (see [1] for more details). Our end
goal here is removing the retrying package from our requirements.

Tenacity provides the same functionality as retrying, but has the
following major differences to account for:
- Tenacity uses seconds rather than ms as retrying did.
- Tenacity has different kwargs for the decorator and
Retrying class itself.
- Tenacity has a different approach for retrying args by
using classes for its stop/wait/retry kwargs.
- By default tenacity raises a RetryError if a retried callable
times out; retrying raises the last exception from the callable.
Tenacity provides backwards compatibility here by offering
the 'reraise' kwarg.
- Tenacity defines 'time.sleep' as a default value for a kwarg.
That said consumers who need to mock patch time.sleep
need to account for this via mocking of time.sleep before
tenacity is imported.
- For retries that check a result, tenacity will raise if the retried
function raises, whereas retrying retried on all exceptions.

This patch updates all usages of retrying with tenacity.
Unit tests will be added/removed where applicable.

[1] https://github.com/jd/tenacity

Closes-Bug: #1635388

Change-Id: Iec0822cc0d5589b04c1764db518478d286455031
changes/38/367638/8
Boden R 6 years ago committed by Rabi Mishra
parent
commit
756dda72d4
  1. 10
      heat/db/sqlalchemy/utils.py
  2. 34
      heat/engine/clients/os/nova.py
  3. 6
      heat/engine/resources/openstack/nova/server_network_mixin.py
  4. 13
      heat/objects/resource.py
  5. 2
      requirements.txt

10
heat/db/sqlalchemy/utils.py

@ -13,9 +13,9 @@
# SQLAlchemy helper functions
import retrying
import sqlalchemy
from sqlalchemy.orm import exc
import tenacity
def clone_table(name, parent, meta, newcols=None, ignorecols=None,
@ -91,8 +91,8 @@ def migrate_data(migrate_engine,
def retry_on_stale_data_error(func):
def is_staledata_error(ex):
return isinstance(ex, exc.StaleDataError)
wrapper = retrying.retry(stop_max_attempt_number=3,
retry_on_exception=is_staledata_error)
wrapper = tenacity.retry(
stop=tenacity.stop_after_attempt(3),
retry=tenacity.retry_if_exception_type(exc.StaleDataError),
reraise=True)
return wrapper(func)

34
heat/engine/clients/os/nova.py

@ -25,9 +25,9 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
from retrying import retry
import six
from six.moves.urllib import parse as urlparse
import tenacity
from heat.common import exception
from heat.common.i18n import _
@ -96,8 +96,12 @@ class NovaClientPlugin(client_plugin.ClientPlugin):
return (isinstance(ex, exceptions.ClientException) and
http_status == 422)
@retry(stop_max_attempt_number=max(cfg.CONF.client_retry_limit + 1, 0),
retry_on_exception=client_plugin.retry_if_connection_err)
@tenacity.retry(
stop=tenacity.stop_after_attempt(
max(cfg.CONF.client_retry_limit + 1, 0)),
retry=tenacity.retry_if_exception(
client_plugin.retry_if_connection_err),
reraise=True)
def get_server(self, server):
"""Return fresh server object.
@ -544,8 +548,12 @@ echo -e '%s\tALL=(ALL)\tNOPASSWD: ALL' >> /etc/sudoers
if len(server.networks[n]) > 0:
return server.networks[n][0]
@retry(stop_max_attempt_number=max(cfg.CONF.client_retry_limit + 1, 0),
retry_on_exception=client_plugin.retry_if_connection_err)
@tenacity.retry(
stop=tenacity.stop_after_attempt(
max(cfg.CONF.client_retry_limit + 1, 0)),
retry=tenacity.retry_if_exception(
client_plugin.retry_if_connection_err),
reraise=True)
def absolute_limits(self):
"""Return the absolute limits as a dictionary."""
limits = self.client().limits.get()
@ -676,9 +684,11 @@ echo -e '%s\tALL=(ALL)\tNOPASSWD: ALL' >> /etc/sudoers
else:
return False
@retry(stop_max_attempt_number=cfg.CONF.max_interface_check_attempts,
wait_fixed=500,
retry_on_result=client_plugin.retry_if_result_is_false)
@tenacity.retry(
stop=tenacity.stop_after_attempt(
cfg.CONF.max_interface_check_attempts),
wait=tenacity.wait_fixed(0.5),
retry=tenacity.retry_if_result(client_plugin.retry_if_result_is_false))
def check_interface_detach(self, server_id, port_id):
server = self.fetch_server(server_id)
if server:
@ -688,9 +698,11 @@ echo -e '%s\tALL=(ALL)\tNOPASSWD: ALL' >> /etc/sudoers
return False
return True
@retry(stop_max_attempt_number=cfg.CONF.max_interface_check_attempts,
wait_fixed=500,
retry_on_result=client_plugin.retry_if_result_is_false)
@tenacity.retry(
stop=tenacity.stop_after_attempt(
cfg.CONF.max_interface_check_attempts),
wait=tenacity.wait_fixed(0.5),
retry=tenacity.retry_if_result(client_plugin.retry_if_result_is_false))
def check_interface_attach(self, server_id, port_id):
server = self.fetch_server(server_id)
if server:

6
heat/engine/resources/openstack/nova/server_network_mixin.py

@ -17,7 +17,7 @@ import eventlet
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import netutils
import retrying
import tenacity
from heat.common import exception
from heat.common.i18n import _
@ -431,7 +431,7 @@ class ServerNetworkMixin(object):
'server %(server)s.')
% {'port': port['id'],
'server': existing_server_id})
except retrying.RetryError:
except tenacity.RetryError:
raise exception.InterfaceDetachFailed(
port=port['id'], server=existing_server_id)
@ -448,7 +448,7 @@ class ServerNetworkMixin(object):
'server %(server)s')
% {'port': port['id'],
'server': prev_server_id})
except retrying.RetryError:
except tenacity.RetryError:
raise exception.InterfaceAttachFailed(
port=port['id'], server=prev_server_id)

13
heat/objects/resource.py

@ -21,8 +21,8 @@ from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_versionedobjects import base
from oslo_versionedobjects import fields
import retrying
import six
import tenacity
from heat.common import crypt
from heat.common import exception
@ -36,11 +36,12 @@ cfg.CONF.import_opt('encrypt_parameters_and_properties', 'heat.common.config')
def retry_on_conflict(func):
def is_conflict(ex):
return isinstance(ex, exception.ConcurrentTransaction)
wrapper = retrying.retry(stop_max_attempt_number=11,
wait_random_min=0.0, wait_random_max=2.0,
retry_on_exception=is_conflict)
wrapper = tenacity.retry(
stop=tenacity.stop_after_attempt(11),
wait=tenacity.wait_random(max=0.002),
retry=tenacity.retry_if_exception_type(
exception.ConcurrentTransaction),
reraise=True)
return wrapper(func)

2
requirements.txt

@ -54,7 +54,7 @@ python-zaqarclient>=1.0.0 # Apache-2.0
pytz>=2013.6 # MIT
PyYAML>=3.10.0 # MIT
requests>=2.10.0 # Apache-2.0
retrying!=1.3.0,>=1.2.3 # Apache-2.0
tenacity>=3.2.1 # Apache-2.0
Routes!=2.0,!=2.1,!=2.3.0,>=1.12.3;python_version=='2.7' # MIT
Routes!=2.0,!=2.3.0,>=1.12.3;python_version!='2.7' # MIT
six>=1.9.0 # MIT

Loading…
Cancel
Save