From: Kevin Benton Date: Tue, 16 Jun 2015 06:10:09 +0000 (-0700) Subject: Retry port status update on StaleDataError X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=3c72832c8b84af673722a34bba25eefc82154b47;p=openstack-build%2Fneutron-build.git Retry port status update on StaleDataError During update_port_status, a port may be concurrently updated/deleted by another process, which will result in a StaleDataError being thrown. In the event it was an update, we want to retry to make sure the port status is set to the desired state so third parties like Nova get notified. This patch uses the oslo_db wrap_db_retry decorator after converting the StaleDataError into a RetryRequest that the decorator can catch. Closes-Bug: #1465407 Change-Id: I0a9230d30f435ec3d48f033136e85c40ad489ef9 --- diff --git a/neutron/db/api.py b/neutron/db/api.py index 3a2752ae1..0b68bd331 100644 --- a/neutron/db/api.py +++ b/neutron/db/api.py @@ -14,10 +14,13 @@ # under the License. import contextlib +import six from oslo_config import cfg +from oslo_db import exception as os_db_exception from oslo_db.sqlalchemy import session from sqlalchemy import exc +from sqlalchemy import orm _FACADE = None @@ -64,3 +67,21 @@ def autonested_transaction(sess): finally: with session_context as tx: yield tx + + +class convert_db_exception_to_retry(object): + """Converts other types of DB exceptions into RetryRequests.""" + + def __init__(self, stale_data=False): + self.to_catch = () + if stale_data: + self.to_catch += (orm.exc.StaleDataError, ) + + def __call__(self, f): + @six.wraps(f) + def wrapper(*args, **kwargs): + try: + return f(*args, **kwargs) + except self.to_catch as e: + raise os_db_exception.RetryRequest(e) + return wrapper diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 2cf2ec80f..00cd60a47 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -1376,7 +1376,9 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return self._bind_port_if_needed(port_context) @oslo_db_api.wrap_db_retry(max_retries=db_api.MAX_RETRIES, - retry_on_deadlock=True) + retry_on_deadlock=True, + retry_on_request=True) + @db_api.convert_db_exception_to_retry(stale_data=True) def update_port_status(self, context, port_id, status, host=None, network=None): """