-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/

-- | Retry combinators for monadic actions that may fail
--   
--   This package 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
--   purpose is to make it easier to work with IO and especially network IO
--   actions that often experience temporary failure and warrant retrying
--   of the original action. For example, a database query may time out for
--   a while, in which case we should hang back for a bit and retry the
--   query instead of simply raising an exception.
@package retry
@version 0.9.3.1

-- | 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.
module Control.Retry

-- | A RetryPolicyM is a function that takes an RetryStatus
--   and possibly returns a delay in microseconds. Iteration numbers start
--   at zero and increase by one on each retry. A *Nothing* return value
--   from the function implies we have reached the retry limit.
--   
--   Please note that RetryPolicyM 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
--   returns Nothing. This can be used to inhibit 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 50000 <> limitRetries 5
--   
--   
--   Naturally, mempty will retry immediately (delay 0) for an
--   unlimited number of retries, forming the identity for the
--   Monoid.
--   
--   The default retry policy retryPolicyDefault implements a
--   constant 50ms delay, up to 5 times:
--   
--   
--   > retryPolicyDefault = constantDelay 50000 <> limitRetries 5
--   
--   
--   For anything more complex, just define your own RetryPolicyM:
--   
--   
--   > myPolicy = retryPolicy $ \ rs -> if rsIterNumber rs > 10 then Just 1000 else Just 10000
--   
--   
--   Since 0.7.
newtype RetryPolicyM (m :: Type -> Type)
RetryPolicyM :: (RetryStatus -> m (Maybe Int)) -> RetryPolicyM (m :: Type -> Type)
[getRetryPolicyM] :: RetryPolicyM (m :: Type -> Type) -> RetryStatus -> m (Maybe Int)

-- | Simplified RetryPolicyM without any use of the monadic context
--   in determining policy. Mostly maintains backwards compatitibility with
--   type signatures pre-0.7.
type RetryPolicy = forall (m :: Type -> Type). Monad m => RetryPolicyM m

-- | Helper for making simplified policies that don't use the monadic
--   context.
retryPolicy :: forall (m :: Type -> Type). Monad m => (RetryStatus -> Maybe Int) -> RetryPolicyM m

-- | Default retry policy
retryPolicyDefault :: forall (m :: Type -> Type). Monad m => RetryPolicyM m

-- | Applies a natural transformation to a policy to run a RetryPolicy
--   meant for the monad m in the monad n provided a
--   transformation from m to n is available. A common
--   case is if you have a pure policy, RetryPolicyM Identity and
--   want to use it to govern an IO computation you could write:
--   
--   
--   purePolicyInIO :: RetryPolicyM Identity -> RetryPolicyM IO
--   purePolicyInIO = natTransformRetryPolicy (pure . runIdentity)
--   
natTransformRetryPolicy :: (forall a. () => m a -> n a) -> RetryPolicyM m -> RetryPolicyM n

-- | How to handle a failed action.
data RetryAction

-- | Don't retry (regardless of what the RetryPolicy says).
DontRetry :: RetryAction

-- | Retry if the RetryPolicy says so, with the delay specified by
--   the policy.
ConsultPolicy :: RetryAction

-- | Retry if the RetryPolicy says so, but override the policy's
--   delay (number of microseconds).
ConsultPolicyOverrideDelay :: Int -> RetryAction

-- | Convert a boolean answer to the question "Should we retry?" into a
--   RetryAction.
toRetryAction :: Bool -> RetryAction

-- | Datatype with stats about retries made thus far.
data RetryStatus
RetryStatus :: !Int -> !Int -> !Maybe Int -> RetryStatus

-- | Iteration number, where 0 is the first try
[rsIterNumber] :: RetryStatus -> !Int

-- | Delay incurred so far from retries in microseconds
[rsCumulativeDelay] :: RetryStatus -> !Int

-- | Latest attempt's delay. Will always be Nothing on first run.
[rsPreviousDelay] :: RetryStatus -> !Maybe Int

-- | Initial, default retry status. Use fields or lenses to update.
defaultRetryStatus :: RetryStatus

-- | Apply policy on status to see what the decision would be.
--   Nothing implies no retry, Just returns updated status.
applyPolicy :: Monad m => RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)

-- | Apply policy and delay by its amount if it results in a retry. Return
--   updated status.
applyAndDelay :: MonadIO m => RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
rsIterNumberL :: Lens' RetryStatus Int
rsCumulativeDelayL :: Lens' RetryStatus Int
rsPreviousDelayL :: Lens' RetryStatus (Maybe Int)

-- | 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 retryPolicyDefault (const $ return . 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.
retrying :: MonadIO m => RetryPolicyM m -> (RetryStatus -> b -> m Bool) -> (RetryStatus -> m b) -> m b

-- | Same as retrying, but with the ability to override the delay of
--   the retry policy based on information obtained after initiation.
--   
--   For example, if the action to run is a HTTP request that turns out to
--   fail with a status code 429 ("too many requests"), the response may
--   contain a "Retry-After" HTTP header which specifies the number of
--   seconds the client should wait until performing the next request. This
--   function allows overriding the delay calculated by the given retry
--   policy with the delay extracted from this header value.
--   
--   In other words, given an arbitrary RetryPolicyM rp,
--   the following invocation will always delay by 1000 microseconds:
--   
--   
--   retryingDynamic rp (\_ _ -> return $ ConsultPolicyOverrideDelay 1000) f
--   
--   
--   Note that a RetryPolicys decision to not perform a retry
--   cannot be overridden. Ie. when to stop retrying is
--   always decided by the retry policy, regardless of the returned
--   RetryAction value.
retryingDynamic :: MonadIO m => RetryPolicyM m -> (RetryStatus -> b -> m RetryAction) -> (RetryStatus -> m b) -> m b

-- | Run an action and recover from a raised exception by potentially
--   retrying the action a number of times. Note that if you're going to
--   use a handler for SomeException, you should add explicit cases
--   *earlier* in the list of handlers to reject AsyncException and
--   SomeAsyncException, as catching these can cause thread and
--   program hangs. recoverAll already does this for you so if you
--   just plan on catching SomeException, you may as well use
--   recoverAll
recovering :: (MonadIO m, MonadMask m) => RetryPolicyM m -> [RetryStatus -> Handler m Bool] -> (RetryStatus -> m a) -> m a

-- | The difference between this and recovering is the same as the
--   difference between retryingDynamic and retrying.
recoveringDynamic :: (MonadIO m, MonadMask m) => RetryPolicyM m -> [RetryStatus -> Handler m RetryAction] -> (RetryStatus -> m a) -> m a

-- | A version of recovering that tries to run the action only a
--   single time. The control will return immediately upon both success and
--   failure. Useful for implementing retry logic in distributed queues and
--   similar external-interfacing systems.
stepping :: (MonadIO m, MonadMask m) => RetryPolicyM m -> [RetryStatus -> Handler m Bool] -> (RetryStatus -> m ()) -> (RetryStatus -> m a) -> RetryStatus -> m (Maybe a)

-- | Retry ALL exceptions that may be raised. To be used with caution; this
--   matches the exception on SomeException. Note that this handler
--   explicitly does not handle AsyncException nor
--   SomeAsyncException (for versions of base >= 4.7). It is not
--   a good idea to catch async exceptions as it can result in hanging
--   threads and programs. Note that if you just throw an exception to this
--   thread that does not descend from SomeException, recoverAll will not
--   catch it.
--   
--   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 retryPolicyDefault f
--   Running action
--   Running action
--   Running action
--   Running action
--   Running action
--   Running action
--   *** Exception: this is an error
--   
recoverAll :: (MonadIO m, MonadMask m) => RetryPolicyM m -> (RetryStatus -> m a) -> m a

-- | List of pre-made handlers that will skip retries on
--   AsyncException and SomeAsyncException. Append your
--   handlers to this list as a convenient way to make sure you're not
--   catching async exceptions like user interrupt.
skipAsyncExceptions :: forall (m :: Type -> Type). MonadIO m => [RetryStatus -> Handler m Bool]

-- | Helper function for constructing handler functions of the form
--   required by recovering.
logRetries :: (Monad m, Exception e) => (e -> m Bool) -> (Bool -> e -> RetryStatus -> m ()) -> RetryStatus -> Handler m Bool

-- | For use with logRetries.
defaultLogMsg :: Exception e => Bool -> e -> RetryStatus -> String
retryOnError :: (Functor m, MonadIO m, MonadError e m) => RetryPolicyM m -> (RetryStatus -> e -> m Bool) -> (RetryStatus -> m a) -> m a

-- | A variant of retrying that allows specifying the initial
--   RetryStatus so that the retrying operation may pick up where it
--   left off in regards to its retry policy.
resumeRetrying :: MonadIO m => RetryStatus -> RetryPolicyM m -> (RetryStatus -> b -> m Bool) -> (RetryStatus -> m b) -> m b

-- | A variant of retryingDynamic that allows specifying the initial
--   RetryStatus so that a retrying operation may pick up where it
--   left off in regards to its retry policy.
resumeRetryingDynamic :: MonadIO m => RetryStatus -> RetryPolicyM m -> (RetryStatus -> b -> m RetryAction) -> (RetryStatus -> m b) -> m b

-- | A variant of recovering that allows specifying the initial
--   RetryStatus so that a recovering operation may pick up where it
--   left off in regards to its retry policy.
resumeRecovering :: (MonadIO m, MonadMask m) => RetryStatus -> RetryPolicyM m -> [RetryStatus -> Handler m Bool] -> (RetryStatus -> m a) -> m a

-- | A variant of recoveringDynamic that allows specifying the
--   initial RetryStatus so that a recovering operation may pick up
--   where it left off in regards to its retry policy.
resumeRecoveringDynamic :: (MonadIO m, MonadMask m) => RetryStatus -> RetryPolicyM m -> [RetryStatus -> Handler m RetryAction] -> (RetryStatus -> m a) -> m a

-- | A variant of recoverAll that allows specifying the initial
--   RetryStatus so that a recovering operation may pick up where it
--   left off in regards to its retry policy.
resumeRecoverAll :: (MonadIO m, MonadMask m) => RetryStatus -> RetryPolicyM m -> (RetryStatus -> m a) -> m a

-- | Implement a constant delay with unlimited retries.
constantDelay :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m

-- | Grow delay exponentially each iteration. Each delay will increase by a
--   factor of two.
exponentialBackoff :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m

-- | FullJitter exponential backoff as explained in AWS Architecture Blog
--   article.
--   
--   
--   http://www.awsarchitectureblog.com/2015/03/backoff.html
--   
--   
--   temp = min(cap, base * 2 ** attempt)
--   
--   sleep = temp / 2 + random_between(0, temp / 2)
fullJitterBackoff :: forall (m :: Type -> Type). MonadIO m => Int -> RetryPolicyM m

-- | Implement Fibonacci backoff.
fibonacciBackoff :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m

-- | Retry immediately, but only up to n times.
limitRetries :: Int -> RetryPolicy

-- | Add an upperbound to a policy such that once the given time-delay
--   amount *per try* has been reached or exceeded, the policy will stop
--   retrying and fail. If you need to stop retrying once *cumulative*
--   delay reaches a time-delay amount, use
--   limitRetriesByCumulativeDelay
limitRetriesByDelay :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m -> RetryPolicyM m

-- | Add an upperbound to a policy such that once the cumulative delay over
--   all retries has reached or exceeded the given limit, the policy will
--   stop retrying and fail.
limitRetriesByCumulativeDelay :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m -> RetryPolicyM m

-- | Set a time-upperbound for any delays that may be directed by the given
--   policy. This function does not terminate the retrying. The policy
--   `capDelay maxDelay (exponentialBackoff n)` will never stop retrying.
--   It will reach a state where it retries forever with a delay of
--   maxDelay between each one. To get termination you need to use
--   one of the limitRetries function variants.
capDelay :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m -> RetryPolicyM m

-- | Run given policy up to N iterations and gather results. In the pair,
--   the Int is the iteration number and the Maybe Int is
--   the delay in microseconds.
simulatePolicy :: Monad m => Int -> RetryPolicyM m -> m [(Int, Maybe Int)]

-- | Run given policy up to N iterations and pretty print results on the
--   console.
simulatePolicyPP :: Int -> RetryPolicyM IO -> IO ()
instance GHC.Classes.Eq Control.Retry.RetryAction
instance GHC.Classes.Eq Control.Retry.RetryStatus
instance GHC.Internal.Generics.Generic Control.Retry.RetryAction
instance GHC.Internal.Generics.Generic Control.Retry.RetryStatus
instance GHC.Internal.Base.Monad m => GHC.Internal.Base.Monoid (Control.Retry.RetryPolicyM m)
instance GHC.Internal.Read.Read Control.Retry.RetryAction
instance GHC.Internal.Read.Read Control.Retry.RetryStatus
instance GHC.Internal.Base.Monad m => GHC.Internal.Base.Semigroup (Control.Retry.RetryPolicyM m)
instance GHC.Internal.Show.Show Control.Retry.RetryAction
instance GHC.Internal.Show.Show Control.Retry.RetryStatus

-- | Unlifted Control.Retry.
module UnliftIO.Retry

-- | A RetryPolicyM is a function that takes an RetryStatus
--   and possibly returns a delay in microseconds. Iteration numbers start
--   at zero and increase by one on each retry. A *Nothing* return value
--   from the function implies we have reached the retry limit.
--   
--   Please note that RetryPolicyM 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
--   returns Nothing. This can be used to inhibit 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 50000 <> limitRetries 5
--   
--   
--   Naturally, mempty will retry immediately (delay 0) for an
--   unlimited number of retries, forming the identity for the
--   Monoid.
--   
--   The default retry policy retryPolicyDefault implements a
--   constant 50ms delay, up to 5 times:
--   
--   
--   > retryPolicyDefault = constantDelay 50000 <> limitRetries 5
--   
--   
--   For anything more complex, just define your own RetryPolicyM:
--   
--   
--   > myPolicy = retryPolicy $ \ rs -> if rsIterNumber rs > 10 then Just 1000 else Just 10000
--   
--   
--   Since 0.7.
newtype RetryPolicyM (m :: Type -> Type)
RetryPolicyM :: (RetryStatus -> m (Maybe Int)) -> RetryPolicyM (m :: Type -> Type)
[getRetryPolicyM] :: RetryPolicyM (m :: Type -> Type) -> RetryStatus -> m (Maybe Int)

-- | Simplified RetryPolicyM without any use of the monadic context
--   in determining policy. Mostly maintains backwards compatitibility with
--   type signatures pre-0.7.
type RetryPolicy = forall (m :: Type -> Type). Monad m => RetryPolicyM m

-- | Helper for making simplified policies that don't use the monadic
--   context.
retryPolicy :: forall (m :: Type -> Type). Monad m => (RetryStatus -> Maybe Int) -> RetryPolicyM m

-- | Default retry policy
retryPolicyDefault :: forall (m :: Type -> Type). Monad m => RetryPolicyM m

-- | Applies a natural transformation to a policy to run a RetryPolicy
--   meant for the monad m in the monad n provided a
--   transformation from m to n is available. A common
--   case is if you have a pure policy, RetryPolicyM Identity and
--   want to use it to govern an IO computation you could write:
--   
--   
--   purePolicyInIO :: RetryPolicyM Identity -> RetryPolicyM IO
--   purePolicyInIO = natTransformRetryPolicy (pure . runIdentity)
--   
natTransformRetryPolicy :: (forall a. () => m a -> n a) -> RetryPolicyM m -> RetryPolicyM n

-- | How to handle a failed action.
data RetryAction

-- | Don't retry (regardless of what the RetryPolicy says).
DontRetry :: RetryAction

-- | Retry if the RetryPolicy says so, with the delay specified by
--   the policy.
ConsultPolicy :: RetryAction

-- | Retry if the RetryPolicy says so, but override the policy's
--   delay (number of microseconds).
ConsultPolicyOverrideDelay :: Int -> RetryAction

-- | Convert a boolean answer to the question "Should we retry?" into a
--   RetryAction.
toRetryAction :: Bool -> RetryAction

-- | Datatype with stats about retries made thus far.
data RetryStatus
RetryStatus :: !Int -> !Int -> !Maybe Int -> RetryStatus

-- | Iteration number, where 0 is the first try
[rsIterNumber] :: RetryStatus -> !Int

-- | Delay incurred so far from retries in microseconds
[rsCumulativeDelay] :: RetryStatus -> !Int

-- | Latest attempt's delay. Will always be Nothing on first run.
[rsPreviousDelay] :: RetryStatus -> !Maybe Int

-- | Initial, default retry status. Use fields or lenses to update.
defaultRetryStatus :: RetryStatus

-- | Apply policy on status to see what the decision would be.
--   Nothing implies no retry, Just returns updated status.
applyPolicy :: Monad m => RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)

-- | Apply policy and delay by its amount if it results in a retry. Return
--   updated status.
applyAndDelay :: MonadIO m => RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
rsIterNumberL :: Lens' RetryStatus Int
rsCumulativeDelayL :: Lens' RetryStatus Int
rsPreviousDelayL :: Lens' RetryStatus (Maybe Int)

-- | 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 retryPolicyDefault (const $ return . 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.
retrying :: MonadIO m => RetryPolicyM m -> (RetryStatus -> b -> m Bool) -> (RetryStatus -> m b) -> m b

-- | Same as retrying, but with the ability to override the delay of
--   the retry policy based on information obtained after initiation.
--   
--   For example, if the action to run is a HTTP request that turns out to
--   fail with a status code 429 ("too many requests"), the response may
--   contain a "Retry-After" HTTP header which specifies the number of
--   seconds the client should wait until performing the next request. This
--   function allows overriding the delay calculated by the given retry
--   policy with the delay extracted from this header value.
--   
--   In other words, given an arbitrary RetryPolicyM rp,
--   the following invocation will always delay by 1000 microseconds:
--   
--   
--   retryingDynamic rp (\_ _ -> return $ ConsultPolicyOverrideDelay 1000) f
--   
--   
--   Note that a RetryPolicys decision to not perform a retry
--   cannot be overridden. Ie. when to stop retrying is
--   always decided by the retry policy, regardless of the returned
--   RetryAction value.
retryingDynamic :: MonadIO m => RetryPolicyM m -> (RetryStatus -> b -> m RetryAction) -> (RetryStatus -> m b) -> m b

-- | Run an action and recover from a raised exception by potentially
--   retrying the action a number of times. Note that if you're going to
--   use a handler for SomeException, you should add explicit
--   cases *earlier* in the list of handlers to reject
--   AsyncException and SomeAsyncException, as catching
--   these can cause thread and program hangs. recoverAll already
--   does this for you so if you just plan on catching
--   SomeException, you may as well use recoverAll
recovering :: MonadUnliftIO m => RetryPolicyM m -> [RetryStatus -> Handler m Bool] -> (RetryStatus -> m a) -> m a

-- | The difference between this and recovering is the same as the
--   difference between retryingDynamic and retrying.
recoveringDynamic :: MonadUnliftIO m => RetryPolicyM m -> [RetryStatus -> Handler m RetryAction] -> (RetryStatus -> m a) -> m a

-- | A version of recovering that tries to run the action only a
--   single time. The control will return immediately upon both success and
--   failure. Useful for implementing retry logic in distributed queues and
--   similar external-interfacing systems.
stepping :: MonadUnliftIO m => RetryPolicyM m -> [RetryStatus -> Handler m Bool] -> (RetryStatus -> m ()) -> (RetryStatus -> m a) -> RetryStatus -> m (Maybe a)

-- | Retry ALL exceptions that may be raised. To be used with caution; this
--   matches the exception on SomeException. Note that this
--   handler explicitly does not handle AsyncException nor
--   SomeAsyncException (for versions of base >= 4.7). It is
--   not a good idea to catch async exceptions as it can result in hanging
--   threads and programs. Note that if you just throw an exception to this
--   thread that does not descend from SomeException, recoverAll will not
--   catch it.
--   
--   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 retryPolicyDefault f
--   Running action
--   Running action
--   Running action
--   Running action
--   Running action
--   Running action
--   *** Exception: this is an error
--   
recoverAll :: MonadUnliftIO m => RetryPolicyM m -> (RetryStatus -> m a) -> m a

-- | List of pre-made handlers that will skip retries on
--   AsyncException and SomeAsyncException. Append your
--   handlers to this list as a convenient way to make sure you're not
--   catching async exceptions like user interrupt.
skipAsyncExceptions :: forall (m :: Type -> Type). MonadIO m => [RetryStatus -> Handler m Bool]

-- | Helper function for constructing handler functions of the form
--   required by recovering.
logRetries :: (Monad m, Exception e) => (e -> m Bool) -> (Bool -> e -> RetryStatus -> m ()) -> RetryStatus -> Handler m Bool

-- | For use with logRetries.
defaultLogMsg :: Exception e => Bool -> e -> RetryStatus -> String
retryOnError :: (Functor m, MonadIO m, MonadError e m) => RetryPolicyM m -> (RetryStatus -> e -> m Bool) -> (RetryStatus -> m a) -> m a

-- | A variant of retrying that allows specifying the initial
--   RetryStatus so that the retrying operation may pick up where it
--   left off in regards to its retry policy.
resumeRetrying :: MonadIO m => RetryStatus -> RetryPolicyM m -> (RetryStatus -> b -> m Bool) -> (RetryStatus -> m b) -> m b

-- | A variant of retryingDynamic that allows specifying the initial
--   RetryStatus so that a retrying operation may pick up where it
--   left off in regards to its retry policy.
resumeRetryingDynamic :: MonadIO m => RetryStatus -> RetryPolicyM m -> (RetryStatus -> b -> m RetryAction) -> (RetryStatus -> m b) -> m b

-- | A variant of recovering that allows specifying the initial
--   RetryStatus so that a recovering operation may pick up where it
--   left off in regards to its retry policy.
resumeRecovering :: MonadUnliftIO m => RetryStatus -> RetryPolicyM m -> [RetryStatus -> Handler m Bool] -> (RetryStatus -> m a) -> m a

-- | A variant of recoveringDynamic that allows specifying the
--   initial RetryStatus so that a recovering operation may pick up
--   where it left off in regards to its retry policy.
resumeRecoveringDynamic :: MonadUnliftIO m => RetryStatus -> RetryPolicyM m -> [RetryStatus -> Handler m RetryAction] -> (RetryStatus -> m a) -> m a

-- | A variant of recoverAll that allows specifying the initial
--   RetryStatus so that a recovering operation may pick up where it
--   left off in regards to its retry policy.
resumeRecoverAll :: MonadUnliftIO m => RetryStatus -> RetryPolicyM m -> (RetryStatus -> m a) -> m a

-- | Implement a constant delay with unlimited retries.
constantDelay :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m

-- | Grow delay exponentially each iteration. Each delay will increase by a
--   factor of two.
exponentialBackoff :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m

-- | FullJitter exponential backoff as explained in AWS Architecture Blog
--   article.
--   
--   
--   http://www.awsarchitectureblog.com/2015/03/backoff.html
--   
--   
--   temp = min(cap, base * 2 ** attempt)
--   
--   sleep = temp / 2 + random_between(0, temp / 2)
fullJitterBackoff :: forall (m :: Type -> Type). MonadIO m => Int -> RetryPolicyM m

-- | Implement Fibonacci backoff.
fibonacciBackoff :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m

-- | Retry immediately, but only up to n times.
limitRetries :: Int -> RetryPolicy

-- | Add an upperbound to a policy such that once the given time-delay
--   amount *per try* has been reached or exceeded, the policy will stop
--   retrying and fail. If you need to stop retrying once *cumulative*
--   delay reaches a time-delay amount, use
--   limitRetriesByCumulativeDelay
limitRetriesByDelay :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m -> RetryPolicyM m

-- | Add an upperbound to a policy such that once the cumulative delay over
--   all retries has reached or exceeded the given limit, the policy will
--   stop retrying and fail.
limitRetriesByCumulativeDelay :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m -> RetryPolicyM m

-- | Set a time-upperbound for any delays that may be directed by the given
--   policy. This function does not terminate the retrying. The policy
--   `capDelay maxDelay (exponentialBackoff n)` will never stop retrying.
--   It will reach a state where it retries forever with a delay of
--   maxDelay between each one. To get termination you need to use
--   one of the limitRetries function variants.
capDelay :: forall (m :: Type -> Type). Monad m => Int -> RetryPolicyM m -> RetryPolicyM m

-- | Run given policy up to N iterations and gather results. In the pair,
--   the Int is the iteration number and the Maybe Int is
--   the delay in microseconds.
simulatePolicy :: Monad m => Int -> RetryPolicyM m -> m [(Int, Maybe Int)]

-- | Run given policy up to N iterations and pretty print results on the
--   console.
simulatePolicyPP :: Int -> RetryPolicyM IO -> IO ()
