retrypy 0.0.33
Python retry utility
License: MIT

A python retry wrapper/decorator
================================

|PyPi Version|
|Travis Test Status|

A simple way to auto retry a funciton that has the possibility of
raising an error. You can either call retry directly or decorate a
function to get it to retry. Intelligent matching logic allows you to
retry certain exception while raising other exceptions.

Call a function directly:
-------------------------

::

    from retrypy import retry, check

    def dummy_func():
        print "dummy_func called..."
        raise Exception("House")

    retry.call(
        dummy_func,
        times=2
    )

    dummy_func called...
    dummy_func called...
    Exception: House

    # usign a check method
    retry.call(
        dummy_func,
        check = check.message_equals("foobar")
    )
    dummy_func called...
    Exception: House

Decorating a function:
----------------------

::

    # Only retry IOErrors
    @retry.decorate(IOError, times=2)
    def dummy_func():
        print "dummy_func called..."
        raise IOError("House")
    dummy_func()

    dummy_func called...
    dummy_func called...
    IOError: House

    # Retry any Exception, use a custom wait function
    @retry.decorate(times=2, wait=lambda n: 2*n)
    def dummy_func():
        print "dummy_func called..."
        raise Exception("House")
    dummy_func()

    dummy_func called...
    dummy_func called...
    Exception: House

Wrap a function and return a new callable:
------------------------------------------

::

    def dummy_func():
        print "dummy_func called..."
        raise Exception("House")

    func = retry.wrap(
        dummy_func,
        times=2
    )
    func()

    dummy_func called...
    dummy_func called...
    Exception: House

Delay Helpers:
--------------

Functions to implement some common backoff strategies: random, exponential, and incremental.

**Random**::

    import time
    from retrypy import retry, delay

    def dummy_func():
        print time.time()
        raise Exception("House")

    retry.call(dummy_func, wait=delay.random(
        min_seconds=1,
        max_seconds=5,
    ))

Output (wait times: .66s, .84s, 3.42s, .33s)::

    1423297137.49
    1423297138.15
    1423297138.99
    1423297142.41
    1423297142.74
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "retrypy/retry.py", line 63, in call
        wait,
      File "retrypy/retry.py", line 29, in _retry
        raise previous_exception
    Exception: House

**Exponential**::

    import time
    from retrypy import retry, delay

    def dummy_func():
        print time.time()
        raise Exception("House")

    retry.call(dummy_func, wait=delay.exponential(
        start_at=1,
    ))

Output (wait times: 1s, 2s, 4s, 8s)::

    1423297238.49
    1423297239.49
    1423297241.49
    1423297245.5
    1423297253.5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "retrypy/retry.py", line 63, in call
        wait,
      File "retrypy/retry.py", line 29, in _retry
        raise previous_exception
    Exception: House

**Incremental**::

    import time
    from retrypy import retry, delay

    def dummy_func():
        print time.time()
        raise Exception("House")

    retry.call(dummy_func, wait=delay.incremental(
      start_at=1,
      step=1,
    ))

Output (wait times: 1s, 2s, 3s, 4s)::

    1423297301.64
    1423297302.64
    1423297304.64
    1423297307.65
    1423297311.65
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "retrypy/retry.py", line 63, in call
        wait,
      File "retrypy/retry.py", line 29, in _retry
        raise previous_exception
    Exception: House


Custom Delay Functions:
-----------------------
You can write your own delay functions, their only requirements are that they take an ``Integer`` and return a ``Number`` of seconds to wait.

::

    def custom_delay(call_count):
        if call_count == 1:
            # don't wait at all the first time
            return 0

        # wait 4, 8, 16, 32
        return 2 ** call_count

        
Builtin Exception Checkers:
---------------------------

Exception Checkers can be used to check if you want to retry a specific exception.  If the check function returns true then the exception is retryable otherwise we will not catch the exception and retry.  The available **checkers** are: ``message_equals``, ``message_contains``, and ``message_matches``.

**message_equals**, will match any ``Exception`` with a message that is identical to the string provided.

**message_contains**, will match any ``Exception`` with a message that contains the string provided.

**message_matches**, will match any ``Exception`` with a message that matches the regex provided.  The regex may be passed as a string or a compiled regex pattern.


Custom Exception Checkers:
--------------------------

You can write your own exception checkers, their only requirements are that they: take an ``Exception`` and an ``Integer`` as parameters.  They should return True if the exception is retryable otherwise False.

::

    def custom_matcher(e, call_count):
        # never fail their first time no matter what
        if call_count == 1:
            return True

        # only retry errors with Bob Barker in the message.
        return "Bob Barker" in str(e):


Installation:
-------------

::

    >> pip install retrypy

Development:
------------

::

    >> git clone https://github.com/toddsifleet/retrypy
    >> cd retrypy
    >> make bootstrap
    >> make

License:
--------

See LICENSE

.. |Travis Test Status| image:: https://travis-ci.org/toddsifleet/retrypy.svg?branch=master
   :target: https://travis-ci.org/toddsifleet/retrypy

.. |PyPi Version| image:: https://badge.fury.io/py/retrypy.svg
   :target: http://badge.fury.io/py/retrypy