Stability | provisional |
---|---|
Maintainer | Ozgun Ataman |
Safe Haskell | Safe-Inferred |
Control.Retry
Description
This module exposes combinators that can wrap arbitrary monadic actions. They run the action and potentially retry running it with some configurable delay for a configurable number of times.
The express purpose of this library is to make it easier to work with IO and especially network IO actions that often experience temporary failure that warrant retrying of the original action. For example, a database query may time out for a while, in which case we should delay a bit and retry the query.
- newtype RetryPolicy = RetryPolicy {
- getRetryPolicy :: Int -> Maybe Int
- retrying :: MonadIO m => RetryPolicy -> (Int -> b -> m Bool) -> m b -> m b
- recovering :: forall m a. (MonadIO m, MonadCatch m) => RetryPolicy -> [Int -> Handler m Bool] -> m a -> m a
- recoverAll :: (MonadIO m, MonadCatch m) => RetryPolicy -> m a -> m a
- constantDelay :: Int -> RetryPolicy
- exponentialBackoff :: Int -> RetryPolicy
- fibonacciBackoff :: Int -> RetryPolicy
- limitRetries :: Int -> RetryPolicy
- capDelay :: Int -> RetryPolicy -> RetryPolicy
- (<>) :: Monoid m => m -> m -> m
High Level Operation
newtype RetryPolicy Source
A RetryPolicy
is a function that takes an iteration number and
possibly returns a delay in miliseconds. *Nothing* implies we have
reached the retry limit.
Please note that RetryPolicy
is a Monoid
. You can collapse
multiple strategies into one using mappend
or <>
. The semantics
of this combination are as follows:
- If either policy returns
Nothing
, the combined policy returnsNothing
. This can be used toinhibit
after a number of retries, for example. - If both policies return a delay, the larger delay will be used. This is quite natural when combining multiple policies to achieve a certain effect.
Example:
One can easily define an exponential backoff policy with a limited number of retries:
> limitedBackoff = exponentialBackoff 50 <> limitedRetries 5
Naturally, mempty
will retry immediately (delay 0) for an
unlimited number of retries, forming the identity for the Monoid
.
The default under def
implements a constant 50ms delay, up to 5 times:
> def = constantDelay 50000 <> limitRetries 5
For anything more complex, just define your own RetryPolicy
:
> myPolicy = RetryPolicy $ \ n -> if n > 10 then Just 1000 else Just 10000
Constructors
RetryPolicy | |
Fields
|
Instances
Arguments
:: MonadIO m | |
=> RetryPolicy | |
-> (Int -> b -> m Bool) | An action to check whether the result should be retried. If True, we delay and retry the operation. |
-> m b | Action to run |
-> m b |
Retry combinator for actions that don't raise exceptions, but
signal in their type the outcome has failed. Examples are the
Maybe
, Either
and EitherT
monads.
Let's write a function that always fails and watch this combinator retry it 5 additional times following the initial run:
>>>
import Data.Maybe
>>>
let f = putStrLn "Running action" >> return Nothing
>>>
retrying def isNothing f
Running action Running action Running action Running action Running action Running action Nothing
Note how the latest failing result is returned after all retries have been exhausted.
Arguments
:: forall m a . (MonadIO m, MonadCatch m) | |
=> RetryPolicy | Just use |
-> [Int -> Handler m Bool] | Should a given exception be retried? Action will be retried if this returns True. |
-> m a | Action to perform |
-> m a |
Run an action and recover from a raised exception by potentially retrying the action a number of times.
recoverAll :: (MonadIO m, MonadCatch m) => RetryPolicy -> m a -> m aSource
Retry ALL exceptions that may be raised. To be used with caution;
this matches the exception on SomeException
.
See how the action below is run once and retried 5 more times before finally failing for good:
>>>
let f = putStrLn "Running action" >> error "this is an error"
>>>
recoverAll def f
Running action Running action Running action Running action Running action Running action *** Exception: this is an error
Retry Policies
Arguments
:: Int | Base delay in microseconds |
-> RetryPolicy |
Implement a constant delay with unlimited retries.
Arguments
:: Int | Base delay in microseconds |
-> RetryPolicy |
Grow delay exponentially each iteration.
Arguments
:: Int | Base delay in microseconds |
-> RetryPolicy |
Implement Fibonacci backoff.
Arguments
:: Int | Maximum number of retries. |
-> RetryPolicy |
Retry immediately, but only up to n
times.
Arguments
:: Int | A maximum delay in microseconds |
-> RetryPolicy | |
-> RetryPolicy |
Set an upperbound for any delays that may be directed by the given policy.