Source code for utah.retry
# Ubuntu Testing Automation Harness
# Copyright 2012 Canonical Ltd.
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
"""Provide a retry loop that exits on success or an unretryable exception."""
import sys
import time
from utah.exceptions import UTAHException
from utah.commandstr import commandstr
[docs]def retry(command, *args, **kw):
"""Retry a command as long as a retriable exception is captured.
A retriable exception is considered to be a
``UTAHException`` that has the attribute ``retry`` set to
``True``.
:param command: Command to be executed.
:type command: callable
:param args: Positional arguments to be passed to the callable.
:type args: tuple
:param kwargs:
Keyword arguments to be passed to the callable.
.. note::
There are a few keywords that are consumed by ``retry`` and not
passed to the callable:
* ``logmethod``: Preferred log method for every retry attempt
(``sys.stderr`` by default)
* ``retry_timeout``: Timeout in seconds between each retry
attempt
:type kwargs: dict
:returns: The value returned by the callable.
.. seealso:: :func:`utah.timeout.timeout`
"""
logmethod = kw.pop('logmethod', sys.stderr.write)
# The following import might cause an ImportError when url_argument is used
# in the config module. To avoid that, a hardcoded default value is used
# for those cases in which the config module hasn't yet been imported.
# The cycle is as follows:
# utah.config -> utah.url -> utah.retry -> utah.config
try:
from utah.config import config
retry_timeout = config.retry_timeout
except ImportError:
retry_timeout = 3
retry_timeout = kw.pop('retry_timeout', retry_timeout)
retval = False
while True:
try:
retval = command(*args, **kw)
return retval
except UTAHException as err:
try:
if err.retry:
if logmethod is not None:
logmethod('Caught {}, retrying {} in {} seconds'
.format(err,
commandstr(command, *args, **kw),
retry_timeout))
time.sleep(retry_timeout)
else:
raise AttributeError
except AttributeError:
raise err