NAME

Try::Tiny::Retry - Extends Try::Tiny to allow retries

VERSION

version 0.004

SYNOPSIS

Use just like Try::Tiny, but with retry instead of try. By default, retry will try 10 times with exponential backoff:

    use Try::Tiny::Retry;

    retry     { ... }
    catch     { ... }
    finally   { ... };

You can retry only if the error matches some conditions:

    use Try::Tiny::Retry;

    retry     { ... }
    retry_if  { /^could not connect/ }
    catch     { ... };

You can customize the number of tries and delay timing:

    use Try::Tiny::Retry ':all';

    retry     { ... }
    delay_exp { 5, 1e6 } # 5 tries, 1 second exponential-backoff
    catch     { ... };

You can run some code before each retry:

    use Try::Tiny::Retry;

    retry     { ... }
    on_retry  { ... }
    catch     { ... };

DESCRIPTION

This module extends Try::Tiny to allow for retrying a block of code several times before failing. Otherwise, it works seamlessly like Try::Tiny.

By default, Try::Tiny::Retry exports retry and retry_if, plus try, catch and finally from Try::Tiny. You can optionally export delay or delay_exp. Or you can get everything with the :all tag.

FUNCTIONS

retry

    retry    { ... }  # code that might fail
    retry_if { ... }  # conditions to be met for a retry
    delay    { ... }  # control repeats and intervals between retries
    catch    { ... }; # handler if all retries fail

The retry function works just like try from Try::Tiny, except that if an exception is thrown, the block may be executed again, depending on the retry_if and delay blocks.

If one or more retry_if blocks are provided, as long as any of them evaluate to true, a retry will be attempted unless the result of the delay block indicates otherwise. If none of them evaluate to true, no retry will be attempted and the delay block will not be called.

If no delay block is provided, the default will be 10 tries with a random delay up to 100 milliseconds with an exponential backoff. (See "delay_exp".) This has an expected cumulative delay of around 25 seconds if all retries fail.

retry_if

    retry    { ... }
    retry_if { /^could not connect/ }
    catch    { ... };

A retry_if block controls whether a retry should be attempted after an exception (assuming there are any retry attempts remaining).

The block is passed the cumulative number of attempts as an argument. The exception caught is provided in $_, just as with catch. It should return a true value if a retry should be attempted.

Multiple retry_if blocks may be provided. Only one needs to evaluate to true to enable a retry.

Using a retry_if block based on the retry count is an alternate way to allow fewer (but not greater) tries than the default delay function, but with the default exponential backoff behavior. These are effectively equivalent:

    retry     { ... }
    retry_if  { shift() < 3 };

    retry     { ... }
    delay_exp { 3, 1e5 };

If you wish the exception to be rethrown if all retry_if blocks return false, you must use a catch block to do so:

    retry    { ... }
    retry_if { /^could not connect/ }
    catch    { die $_ };

on_retry

    retry    { ... }
    on_retry { $state->reset() }
    catch    { ... };

The on_retry block runs before each retry block after the first attempt. The exception caught is provided in $_. The block is passed the cumulative number of attempts as an argument. The return value is ignored.

Only one on_retry block is allowed.

delay

    retry { ... }
    delay {
        return if $_[0] >= 3; # only three tries
        sleep 1;              # constant delay between tries
    }
    catch { ... };

The delay block controls the number of attempts and the delay between attempts.

The block is passed the cumulative number of attempts as an argument. If the delay block returns an undefined value, no further retries will be made.

If you wish the exception to be rethrown if all attempts fail, you must use a catch block to do so:

    retry    { ... }
    delay    { ... }
    catch    { die $_ };

Only one delay block is allowed.

delay_exp

    retry     { ... }
    delay_exp { 3, 10000 } # 3 tries, 10000 µsec
    catch     { ... };

This function is an exponential-backoff delay-function generator. The delay between attempts is randomly selected between 0 and an upper bound. The upper bound doubles after each failure.

It requires a code block as an argument. The block will be evaluated in list context and must return two elements. The first element is the number of tries allowed. The second element is the starting upper bound in microseconds.

Given number of tries N and upper bound U, the expected cumulative delay time if all attempts fail is 0.5 * U * ( 2^(N-1) - 1 ).

SEE ALSO

There are other retry modules on CPAN, but none of them worked seamlessly with Try::Tiny.

  • Action::Retry — OO (Moo) or functional; various delay strategies; supports conditions

  • AnyEvent::Retry — OO (Moose) and event-driven; various delay strategies

  • Attempt — functional; simple retry count with constant sleep time

  • Retry — OO (Moose) with fixed exponential backoff; supports callbacks on every iteration

  • Sub::Retry — functional; simple retry count with constant sleep time; supports conditions

SUPPORT

Bugs / Feature Requests

Please report any bugs or feature requests through the issue tracker at https://github.com/dagolden/Try-Tiny-Retry/issues. You will be notified automatically of any progress on your issue.

Source Code

This is open source software. The code repository is available for public review and contribution under the terms of the license.

https://github.com/dagolden/Try-Tiny-Retry

  git clone https://github.com/dagolden/Try-Tiny-Retry.git

AUTHOR

David Golden <dagolden@cpan.org>

CONTRIBUTOR

David Steinbrunner <dsteinbrunner@pobox.com>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2013 by David Golden.

This is free software, licensed under:

  The Apache License, Version 2.0, January 2004