Stability | provisional |
---|---|
Maintainer | Ozgun Ataman |
Safe Haskell | Safe-Inferred |
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.
- data RetrySettings = RetrySettings {
- numRetries :: RetryLimit
- backoff :: Bool
- baseDelay :: Int
- data RetryLimit
- limitedRetries :: Int -> RetryLimit
- unlimitedRetries :: RetryLimit
- retrying :: MonadIO m => RetrySettings -> (b -> Bool) -> m b -> m b
- recovering :: forall m a. (MonadIO m, MonadBaseControl IO m) => RetrySettings -> [Handler m Bool] -> m a -> m a
- recoverAll :: (MonadIO m, MonadBaseControl IO m) => RetrySettings -> m a -> m a
- delay :: RetrySettings -> Int
- performDelay :: MonadIO m => RetrySettings -> Int -> m ()
- flatDelay :: MonadIO m => RetrySettings -> t -> m ()
- backoffDelay :: (Integral b, MonadIO m) => RetrySettings -> b -> m ()
High Level Operation
data RetrySettings Source
Settings for retry behavior. Simply using def
for default
values should work in most cases.
RetrySettings | |
|
data RetryLimit Source
limitedRetries :: Int -> RetryLimitSource
Set a limited number of retries. Default in def
is 5.
unlimitedRetries :: RetryLimitSource
Set an unlimited number of retries. Note that with this option turned on, the combinator will keep retrying the action indefinitely and might essentially hang in some cases.
:: MonadIO m | |
=> RetrySettings | |
-> (b -> Bool) | A function 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.
:: forall m a . (MonadIO m, MonadBaseControl IO m) | |
=> RetrySettings | Just use |
-> [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, MonadBaseControl IO m) => RetrySettings -> 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
Utilities
delay :: RetrySettings -> IntSource
Delay in micro seconds
performDelay :: MonadIO m => RetrySettings -> Int -> m ()Source
Perform threadDelay
for the nth retry for the given settings.
flatDelay :: MonadIO m => RetrySettings -> t -> m ()Source
Delay thread using flat delay
backoffDelay :: (Integral b, MonadIO m) => RetrySettings -> b -> m ()Source
Delay thread using backoff delay for the nth retry.