retry-0.5: Retry combinators for monadic actions that may fail

Stabilityprovisional
MaintainerOzgun Ataman
Safe HaskellSafe-Inferred

Control.Retry

Contents

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.

Synopsis

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:

  1. If either policy returns Nothing, the combined policy returns Nothing. This can be used to inhibit after a number of retries, for example.
  2. 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

getRetryPolicy :: Int -> Maybe Int
 

retryingSource

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.

recoveringSource

Arguments

:: forall m a . (MonadIO m, MonadCatch m) 
=> RetryPolicy

Just use def faor default settings

-> [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

constantDelaySource

Arguments

:: Int

Base delay in microseconds

-> RetryPolicy 

Implement a constant delay with unlimited retries.

exponentialBackoffSource

Arguments

:: Int

Base delay in microseconds

-> RetryPolicy 

Grow delay exponentially each iteration.

fibonacciBackoffSource

Arguments

:: Int

Base delay in microseconds

-> RetryPolicy 

Implement Fibonacci backoff.

limitRetriesSource

Arguments

:: Int

Maximum number of retries.

-> RetryPolicy 

Retry immediately, but only up to n times.

Re-export from Data.Monoid

(<>) :: Monoid m => m -> m -> m

An infix synonym for mappend.