'Ensure operation completes.
Regardless of any channel/connection errors occurring.
Retries by establishing the connection, and reapplying
the function.
Arguments:
fun (Callable): Method to apply.
errback (Callable): Optional callback called each time the
connection can\'t be established.  Arguments provided are
the exception raised and the interval that will
be slept ``(exc, interval)``.
max_retries (int): Maximum number of times to retry.
If this limit is exceeded the connection error
will be re-raised.
interval_start (float): The number of seconds we start
sleeping for.
interval_step (float): How many seconds added to the interval
for each retry.
interval_max (float): Maximum number of seconds to sleep between
each retry.
Examples:
>>> from kombu import Connection, Producer
>>> conn = Connection(\'amqp://\')
>>> producer = Producer(conn)
>>> def errback(exc, interval):
...     logger.error(\'Error: %r\', exc, exc_info=1)
...     logger.info(\'Retry in %s seconds.\', interval)
>>> publish = conn.ensure(producer, producer.publish,
...                       errback=errback, max_retries=3)
>>> publish({\'hello\': \'world\'}, routing_key=\'dest\')'

def ensure(self, obj, fun, errback=None, max_retries=None, interval_start=1, interval_step=1, interval_max=1, on_revive=None):

    def _ensured(*args, **kwargs):
        got_connection = 0
        conn_errors = self.recoverable_connection_errors
        chan_errors = self.recoverable_channel_errors
        has_modern_errors = hasattr(self.transport, u'recoverable_connection_errors')
        with self._reraise_as_library_errors():
            for retries in count(0):
                try:
                    return fun(*args, **kwargs)
                except conn_errors as exc:
                    if (got_connection and (not has_modern_errors)):
                        raise
                    if ((max_retries is not None) and (retries > max_retries)):
                        raise
                    self._debug(u'ensure    connection    error:    %r', exc, exc_info=1)
                    self.collect()
                    (errback and errback(exc, 0))
                    remaining_retries = None
                    if (max_retries is not None):
                        remaining_retries = max((max_retries - retries), 1)
                    self.ensure_connection(errback, remaining_retries, interval_start, interval_step, interval_max, reraise_as_library_errors=False)
                    channel = self.default_channel
                    obj.revive(channel)
                    if on_revive:
                        on_revive(channel)
                    got_connection += 1
                except chan_errors as exc:
                    if ((max_retries is not None) and (retries > max_retries)):
                        raise
                    self._debug(u'ensure    channel    error:    %r', exc, exc_info=1)
                    (errback and errback(exc, 0))
    _ensured.__name__ = bytes_if_py2(u'{0}(ensured)'.format(fun.__name__))
    _ensured.__doc__ = fun.__doc__
    _ensured.__module__ = fun.__module__
    return _ensured
