{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE ViewPatterns #-}
module Control.Retry
(
RetryPolicyM (..)
, RetryPolicy
, retryPolicy
, retryPolicyDefault
, natTransformRetryPolicy
, RetryAction (..)
, toRetryAction
, RetryStatus (..)
, defaultRetryStatus
, applyPolicy
, applyAndDelay
, rsIterNumberL
, rsCumulativeDelayL
, rsPreviousDelayL
, retrying
, retryingDynamic
, recovering
, recoveringDynamic
, stepping
, recoverAll
, skipAsyncExceptions
, logRetries
, defaultLogMsg
, resumeRetrying
, resumeRetryingDynamic
, resumeRecovering
, resumeRecoveringDynamic
, resumeRecoverAll
, constantDelay
, exponentialBackoff
, fullJitterBackoff
, fibonacciBackoff
, limitRetries
, limitRetriesByDelay
, limitRetriesByCumulativeDelay
, capDelay
, simulatePolicy
, simulatePolicyPP
) where
import Control.Applicative
import Control.Concurrent
#if MIN_VERSION_base(4, 7, 0)
import Control.Exception (AsyncException, SomeAsyncException)
#else
import Control.Exception (AsyncException)
#endif
import Control.Monad
import Control.Monad.Catch
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.State
import Data.List (foldl')
import Data.Maybe
import GHC.Generics
import GHC.Prim
import GHC.Types (Int(I#))
import System.Random
# if MIN_VERSION_base(4, 9, 0)
import Data.Semigroup
# else
import Data.Monoid
# endif
import Prelude
newtype RetryPolicyM m = RetryPolicyM { RetryPolicyM m -> RetryStatus -> m (Maybe Int)
getRetryPolicyM :: RetryStatus -> m (Maybe Int) }
type RetryPolicy = forall m . Monad m => RetryPolicyM m
retryPolicyDefault :: (Monad m) => RetryPolicyM m
retryPolicyDefault :: RetryPolicyM m
retryPolicyDefault = Int -> RetryPolicyM m
forall (m :: * -> *). Monad m => Int -> RetryPolicyM m
constantDelay Int
50000 RetryPolicyM m -> RetryPolicyM m -> RetryPolicyM m
forall a. Semigroup a => a -> a -> a
<> Int -> RetryPolicy
limitRetries Int
5
# if MIN_VERSION_base(4, 9, 0)
instance Monad m => Semigroup (RetryPolicyM m) where
(RetryPolicyM RetryStatus -> m (Maybe Int)
a) <> :: RetryPolicyM m -> RetryPolicyM m -> RetryPolicyM m
<> (RetryPolicyM RetryStatus -> m (Maybe Int)
b) = (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall (m :: * -> *).
(RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
RetryPolicyM ((RetryStatus -> m (Maybe Int)) -> RetryPolicyM m)
-> (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \ RetryStatus
n -> MaybeT m Int -> m (Maybe Int)
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT (MaybeT m Int -> m (Maybe Int)) -> MaybeT m Int -> m (Maybe Int)
forall a b. (a -> b) -> a -> b
$ do
Int
a' <- m (Maybe Int) -> MaybeT m Int
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (m (Maybe Int) -> MaybeT m Int) -> m (Maybe Int) -> MaybeT m Int
forall a b. (a -> b) -> a -> b
$ RetryStatus -> m (Maybe Int)
a RetryStatus
n
Int
b' <- m (Maybe Int) -> MaybeT m Int
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (m (Maybe Int) -> MaybeT m Int) -> m (Maybe Int) -> MaybeT m Int
forall a b. (a -> b) -> a -> b
$ RetryStatus -> m (Maybe Int)
b RetryStatus
n
Int -> MaybeT m Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> MaybeT m Int) -> Int -> MaybeT m Int
forall a b. (a -> b) -> a -> b
$! Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
a' Int
b'
instance Monad m => Monoid (RetryPolicyM m) where
mempty :: RetryPolicyM m
mempty = (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall (m :: * -> *).
Monad m =>
(RetryStatus -> Maybe Int) -> RetryPolicyM m
retryPolicy ((RetryStatus -> Maybe Int) -> RetryPolicyM m)
-> (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ Maybe Int -> RetryStatus -> Maybe Int
forall a b. a -> b -> a
const (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
0)
mappend :: RetryPolicyM m -> RetryPolicyM m -> RetryPolicyM m
mappend = RetryPolicyM m -> RetryPolicyM m -> RetryPolicyM m
forall a. Semigroup a => a -> a -> a
(<>)
# else
instance Monad m => Monoid (RetryPolicyM m) where
mempty = retryPolicy $ const (Just 0)
(RetryPolicyM a) `mappend` (RetryPolicyM b) = RetryPolicyM $ \ n -> runMaybeT $ do
a' <- MaybeT $ a n
b' <- MaybeT $ b n
return $! max a' b'
#endif
natTransformRetryPolicy :: (forall a. m a -> n a) -> RetryPolicyM m -> RetryPolicyM n
natTransformRetryPolicy :: (forall a. m a -> n a) -> RetryPolicyM m -> RetryPolicyM n
natTransformRetryPolicy forall a. m a -> n a
f (RetryPolicyM RetryStatus -> m (Maybe Int)
p) = (RetryStatus -> n (Maybe Int)) -> RetryPolicyM n
forall (m :: * -> *).
(RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
RetryPolicyM ((RetryStatus -> n (Maybe Int)) -> RetryPolicyM n)
-> (RetryStatus -> n (Maybe Int)) -> RetryPolicyM n
forall a b. (a -> b) -> a -> b
$ \RetryStatus
stat -> m (Maybe Int) -> n (Maybe Int)
forall a. m a -> n a
f (RetryStatus -> m (Maybe Int)
p RetryStatus
stat)
modifyRetryPolicyDelay :: Functor m => (Int -> Int) -> RetryPolicyM m -> RetryPolicyM m
modifyRetryPolicyDelay :: (Int -> Int) -> RetryPolicyM m -> RetryPolicyM m
modifyRetryPolicyDelay Int -> Int
f (RetryPolicyM RetryStatus -> m (Maybe Int)
p) = (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall (m :: * -> *).
(RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
RetryPolicyM ((RetryStatus -> m (Maybe Int)) -> RetryPolicyM m)
-> (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \RetryStatus
stat -> (Int -> Int) -> Maybe Int -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int -> Int
f (Maybe Int -> Maybe Int) -> m (Maybe Int) -> m (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RetryStatus -> m (Maybe Int)
p RetryStatus
stat
data RetryAction
= DontRetry
| ConsultPolicy
| ConsultPolicyOverrideDelay Int
deriving (ReadPrec [RetryAction]
ReadPrec RetryAction
Int -> ReadS RetryAction
ReadS [RetryAction]
(Int -> ReadS RetryAction)
-> ReadS [RetryAction]
-> ReadPrec RetryAction
-> ReadPrec [RetryAction]
-> Read RetryAction
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [RetryAction]
$creadListPrec :: ReadPrec [RetryAction]
readPrec :: ReadPrec RetryAction
$creadPrec :: ReadPrec RetryAction
readList :: ReadS [RetryAction]
$creadList :: ReadS [RetryAction]
readsPrec :: Int -> ReadS RetryAction
$creadsPrec :: Int -> ReadS RetryAction
Read, Int -> RetryAction -> ShowS
[RetryAction] -> ShowS
RetryAction -> String
(Int -> RetryAction -> ShowS)
-> (RetryAction -> String)
-> ([RetryAction] -> ShowS)
-> Show RetryAction
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RetryAction] -> ShowS
$cshowList :: [RetryAction] -> ShowS
show :: RetryAction -> String
$cshow :: RetryAction -> String
showsPrec :: Int -> RetryAction -> ShowS
$cshowsPrec :: Int -> RetryAction -> ShowS
Show, RetryAction -> RetryAction -> Bool
(RetryAction -> RetryAction -> Bool)
-> (RetryAction -> RetryAction -> Bool) -> Eq RetryAction
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RetryAction -> RetryAction -> Bool
$c/= :: RetryAction -> RetryAction -> Bool
== :: RetryAction -> RetryAction -> Bool
$c== :: RetryAction -> RetryAction -> Bool
Eq, (forall x. RetryAction -> Rep RetryAction x)
-> (forall x. Rep RetryAction x -> RetryAction)
-> Generic RetryAction
forall x. Rep RetryAction x -> RetryAction
forall x. RetryAction -> Rep RetryAction x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep RetryAction x -> RetryAction
$cfrom :: forall x. RetryAction -> Rep RetryAction x
Generic)
toRetryAction :: Bool -> RetryAction
toRetryAction :: Bool -> RetryAction
toRetryAction Bool
False = RetryAction
DontRetry
toRetryAction Bool
True = RetryAction
ConsultPolicy
data RetryStatus = RetryStatus
{ RetryStatus -> Int
rsIterNumber :: !Int
, RetryStatus -> Int
rsCumulativeDelay :: !Int
, RetryStatus -> Maybe Int
rsPreviousDelay :: !(Maybe Int)
} deriving (ReadPrec [RetryStatus]
ReadPrec RetryStatus
Int -> ReadS RetryStatus
ReadS [RetryStatus]
(Int -> ReadS RetryStatus)
-> ReadS [RetryStatus]
-> ReadPrec RetryStatus
-> ReadPrec [RetryStatus]
-> Read RetryStatus
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [RetryStatus]
$creadListPrec :: ReadPrec [RetryStatus]
readPrec :: ReadPrec RetryStatus
$creadPrec :: ReadPrec RetryStatus
readList :: ReadS [RetryStatus]
$creadList :: ReadS [RetryStatus]
readsPrec :: Int -> ReadS RetryStatus
$creadsPrec :: Int -> ReadS RetryStatus
Read, Int -> RetryStatus -> ShowS
[RetryStatus] -> ShowS
RetryStatus -> String
(Int -> RetryStatus -> ShowS)
-> (RetryStatus -> String)
-> ([RetryStatus] -> ShowS)
-> Show RetryStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RetryStatus] -> ShowS
$cshowList :: [RetryStatus] -> ShowS
show :: RetryStatus -> String
$cshow :: RetryStatus -> String
showsPrec :: Int -> RetryStatus -> ShowS
$cshowsPrec :: Int -> RetryStatus -> ShowS
Show, RetryStatus -> RetryStatus -> Bool
(RetryStatus -> RetryStatus -> Bool)
-> (RetryStatus -> RetryStatus -> Bool) -> Eq RetryStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RetryStatus -> RetryStatus -> Bool
$c/= :: RetryStatus -> RetryStatus -> Bool
== :: RetryStatus -> RetryStatus -> Bool
$c== :: RetryStatus -> RetryStatus -> Bool
Eq, (forall x. RetryStatus -> Rep RetryStatus x)
-> (forall x. Rep RetryStatus x -> RetryStatus)
-> Generic RetryStatus
forall x. Rep RetryStatus x -> RetryStatus
forall x. RetryStatus -> Rep RetryStatus x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep RetryStatus x -> RetryStatus
$cfrom :: forall x. RetryStatus -> Rep RetryStatus x
Generic)
defaultRetryStatus :: RetryStatus
defaultRetryStatus :: RetryStatus
defaultRetryStatus = Int -> Int -> Maybe Int -> RetryStatus
RetryStatus Int
0 Int
0 Maybe Int
forall a. Maybe a
Nothing
rsIterNumberL :: Lens' RetryStatus Int
rsIterNumberL :: (Int -> f Int) -> RetryStatus -> f RetryStatus
rsIterNumberL = (RetryStatus -> Int)
-> (RetryStatus -> Int -> RetryStatus)
-> Lens RetryStatus RetryStatus Int Int
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens RetryStatus -> Int
rsIterNumber (\RetryStatus
rs Int
x -> RetryStatus
rs { rsIterNumber :: Int
rsIterNumber = Int
x })
{-# INLINE rsIterNumberL #-}
rsCumulativeDelayL :: Lens' RetryStatus Int
rsCumulativeDelayL :: (Int -> f Int) -> RetryStatus -> f RetryStatus
rsCumulativeDelayL = (RetryStatus -> Int)
-> (RetryStatus -> Int -> RetryStatus)
-> Lens RetryStatus RetryStatus Int Int
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens RetryStatus -> Int
rsCumulativeDelay (\RetryStatus
rs Int
x -> RetryStatus
rs { rsCumulativeDelay :: Int
rsCumulativeDelay = Int
x })
{-# INLINE rsCumulativeDelayL #-}
rsPreviousDelayL :: Lens' RetryStatus (Maybe Int)
rsPreviousDelayL :: (Maybe Int -> f (Maybe Int)) -> RetryStatus -> f RetryStatus
rsPreviousDelayL = (RetryStatus -> Maybe Int)
-> (RetryStatus -> Maybe Int -> RetryStatus)
-> Lens RetryStatus RetryStatus (Maybe Int) (Maybe Int)
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens RetryStatus -> Maybe Int
rsPreviousDelay (\RetryStatus
rs Maybe Int
x -> RetryStatus
rs { rsPreviousDelay :: Maybe Int
rsPreviousDelay = Maybe Int
x })
{-# INLINE rsPreviousDelayL #-}
applyPolicy
:: Monad m
=> RetryPolicyM m
-> RetryStatus
-> m (Maybe RetryStatus)
applyPolicy :: RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
applyPolicy (RetryPolicyM RetryStatus -> m (Maybe Int)
policy) RetryStatus
s = do
Maybe Int
res <- RetryStatus -> m (Maybe Int)
policy RetryStatus
s
case Maybe Int
res of
Just Int
delay -> Maybe RetryStatus -> m (Maybe RetryStatus)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe RetryStatus -> m (Maybe RetryStatus))
-> Maybe RetryStatus -> m (Maybe RetryStatus)
forall a b. (a -> b) -> a -> b
$! RetryStatus -> Maybe RetryStatus
forall a. a -> Maybe a
Just (RetryStatus -> Maybe RetryStatus)
-> RetryStatus -> Maybe RetryStatus
forall a b. (a -> b) -> a -> b
$! RetryStatus :: Int -> Int -> Maybe Int -> RetryStatus
RetryStatus
{ rsIterNumber :: Int
rsIterNumber = RetryStatus -> Int
rsIterNumber RetryStatus
s Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
, rsCumulativeDelay :: Int
rsCumulativeDelay = RetryStatus -> Int
rsCumulativeDelay RetryStatus
s Int -> Int -> Int
`boundedPlus` Int
delay
, rsPreviousDelay :: Maybe Int
rsPreviousDelay = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
delay }
Maybe Int
Nothing -> Maybe RetryStatus -> m (Maybe RetryStatus)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe RetryStatus
forall a. Maybe a
Nothing
applyAndDelay
:: MonadIO m
=> RetryPolicyM m
-> RetryStatus
-> m (Maybe RetryStatus)
applyAndDelay :: RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
applyAndDelay RetryPolicyM m
policy RetryStatus
s = do
Maybe RetryStatus
chk <- RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
forall (m :: * -> *).
Monad m =>
RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
applyPolicy RetryPolicyM m
policy RetryStatus
s
case Maybe RetryStatus
chk of
Just RetryStatus
rs -> do
case RetryStatus -> Maybe Int
rsPreviousDelay RetryStatus
rs of
Maybe Int
Nothing -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just Int
delay -> IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ Int -> IO ()
threadDelay Int
delay
Maybe RetryStatus -> m (Maybe RetryStatus)
forall (m :: * -> *) a. Monad m => a -> m a
return (RetryStatus -> Maybe RetryStatus
forall a. a -> Maybe a
Just RetryStatus
rs)
Maybe RetryStatus
Nothing -> Maybe RetryStatus -> m (Maybe RetryStatus)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe RetryStatus
forall a. Maybe a
Nothing
retryPolicy :: (Monad m) => (RetryStatus -> Maybe Int) -> RetryPolicyM m
retryPolicy :: (RetryStatus -> Maybe Int) -> RetryPolicyM m
retryPolicy RetryStatus -> Maybe Int
f = (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall (m :: * -> *).
(RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
RetryPolicyM ((RetryStatus -> m (Maybe Int)) -> RetryPolicyM m)
-> (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \ RetryStatus
s -> Maybe Int -> m (Maybe Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (RetryStatus -> Maybe Int
f RetryStatus
s)
limitRetries
:: Int
-> RetryPolicy
limitRetries :: Int -> RetryPolicy
limitRetries Int
i = (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall (m :: * -> *).
Monad m =>
(RetryStatus -> Maybe Int) -> RetryPolicyM m
retryPolicy ((RetryStatus -> Maybe Int) -> RetryPolicyM m)
-> (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \ RetryStatus { rsIterNumber :: RetryStatus -> Int
rsIterNumber = Int
n} -> if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
i then Maybe Int
forall a. Maybe a
Nothing else Int -> Maybe Int
forall a. a -> Maybe a
Just Int
0
limitRetriesByDelay
:: Monad m
=> Int
-> RetryPolicyM m
-> RetryPolicyM m
limitRetriesByDelay :: Int -> RetryPolicyM m -> RetryPolicyM m
limitRetriesByDelay Int
i RetryPolicyM m
p = (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall (m :: * -> *).
(RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
RetryPolicyM ((RetryStatus -> m (Maybe Int)) -> RetryPolicyM m)
-> (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \ RetryStatus
n ->
(Maybe Int -> (Int -> Maybe Int) -> Maybe Int
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Maybe Int
limit) (Maybe Int -> Maybe Int) -> m (Maybe Int) -> m (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` RetryPolicyM m -> RetryStatus -> m (Maybe Int)
forall (m :: * -> *).
RetryPolicyM m -> RetryStatus -> m (Maybe Int)
getRetryPolicyM RetryPolicyM m
p RetryStatus
n
where
limit :: Int -> Maybe Int
limit Int
delay = if Int
delay Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
i then Maybe Int
forall a. Maybe a
Nothing else Int -> Maybe Int
forall a. a -> Maybe a
Just Int
delay
limitRetriesByCumulativeDelay
:: Monad m
=> Int
-> RetryPolicyM m
-> RetryPolicyM m
limitRetriesByCumulativeDelay :: Int -> RetryPolicyM m -> RetryPolicyM m
limitRetriesByCumulativeDelay Int
cumulativeLimit RetryPolicyM m
p = (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall (m :: * -> *).
(RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
RetryPolicyM ((RetryStatus -> m (Maybe Int)) -> RetryPolicyM m)
-> (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \ RetryStatus
stat ->
(Maybe Int -> (Int -> Maybe Int) -> Maybe Int
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= RetryStatus -> Int -> Maybe Int
limit RetryStatus
stat) (Maybe Int -> Maybe Int) -> m (Maybe Int) -> m (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` RetryPolicyM m -> RetryStatus -> m (Maybe Int)
forall (m :: * -> *).
RetryPolicyM m -> RetryStatus -> m (Maybe Int)
getRetryPolicyM RetryPolicyM m
p RetryStatus
stat
where
limit :: RetryStatus -> Int -> Maybe Int
limit RetryStatus
status Int
curDelay
| RetryStatus -> Int
rsCumulativeDelay RetryStatus
status Int -> Int -> Int
`boundedPlus` Int
curDelay Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
cumulativeLimit = Maybe Int
forall a. Maybe a
Nothing
| Bool
otherwise = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
curDelay
constantDelay
:: (Monad m)
=> Int
-> RetryPolicyM m
constantDelay :: Int -> RetryPolicyM m
constantDelay Int
delay = (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall (m :: * -> *).
Monad m =>
(RetryStatus -> Maybe Int) -> RetryPolicyM m
retryPolicy (Maybe Int -> RetryStatus -> Maybe Int
forall a b. a -> b -> a
const (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
delay))
exponentialBackoff
:: (Monad m)
=> Int
-> RetryPolicyM m
exponentialBackoff :: Int -> RetryPolicyM m
exponentialBackoff Int
base = (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall (m :: * -> *).
Monad m =>
(RetryStatus -> Maybe Int) -> RetryPolicyM m
retryPolicy ((RetryStatus -> Maybe Int) -> RetryPolicyM m)
-> (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \ RetryStatus { rsIterNumber :: RetryStatus -> Int
rsIterNumber = Int
n } ->
Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$! Int
base Int -> Int -> Int
`boundedMult` Int -> Int -> Int
boundedPow Int
2 Int
n
fullJitterBackoff
:: (MonadIO m)
=> Int
-> RetryPolicyM m
fullJitterBackoff :: Int -> RetryPolicyM m
fullJitterBackoff Int
base = (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall (m :: * -> *).
(RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
RetryPolicyM ((RetryStatus -> m (Maybe Int)) -> RetryPolicyM m)
-> (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \ RetryStatus { rsIterNumber :: RetryStatus -> Int
rsIterNumber = Int
n } -> do
let d :: Int
d = (Int
base Int -> Int -> Int
`boundedMult` Int -> Int -> Int
boundedPow Int
2 Int
n) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2
Int
rand <- IO Int -> m Int
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Int -> m Int) -> IO Int -> m Int
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> IO Int
forall a (m :: * -> *). (Random a, MonadIO m) => (a, a) -> m a
randomRIO (Int
0, Int
d)
Maybe Int -> m (Maybe Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Int -> m (Maybe Int)) -> Maybe Int -> m (Maybe Int)
forall a b. (a -> b) -> a -> b
$! Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$! Int
d Int -> Int -> Int
`boundedPlus` Int
rand
fibonacciBackoff
:: (Monad m)
=> Int
-> RetryPolicyM m
fibonacciBackoff :: Int -> RetryPolicyM m
fibonacciBackoff Int
base = (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall (m :: * -> *).
Monad m =>
(RetryStatus -> Maybe Int) -> RetryPolicyM m
retryPolicy ((RetryStatus -> Maybe Int) -> RetryPolicyM m)
-> (RetryStatus -> Maybe Int) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \RetryStatus { rsIterNumber :: RetryStatus -> Int
rsIterNumber = Int
n } ->
Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ Int -> (Int, Int) -> Int
forall t. (Eq t, Num t) => t -> (Int, Int) -> Int
fib (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
0, Int
base)
where
fib :: t -> (Int, Int) -> Int
fib t
0 (Int
a, Int
_) = Int
a
fib !t
m (!Int
a, !Int
b) = t -> (Int, Int) -> Int
fib (t
mt -> t -> t
forall a. Num a => a -> a -> a
-t
1) (Int
b, Int
a Int -> Int -> Int
`boundedPlus` Int
b)
capDelay
:: Monad m
=> Int
-> RetryPolicyM m
-> RetryPolicyM m
capDelay :: Int -> RetryPolicyM m -> RetryPolicyM m
capDelay Int
limit RetryPolicyM m
p = (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall (m :: * -> *).
(RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
RetryPolicyM ((RetryStatus -> m (Maybe Int)) -> RetryPolicyM m)
-> (RetryStatus -> m (Maybe Int)) -> RetryPolicyM m
forall a b. (a -> b) -> a -> b
$ \ RetryStatus
n ->
(Int -> Int) -> Maybe Int -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
limit) (Maybe Int -> Maybe Int) -> m (Maybe Int) -> m (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` RetryPolicyM m -> RetryStatus -> m (Maybe Int)
forall (m :: * -> *).
RetryPolicyM m -> RetryStatus -> m (Maybe Int)
getRetryPolicyM RetryPolicyM m
p RetryStatus
n
retrying :: MonadIO m
=> RetryPolicyM m
-> (RetryStatus -> b -> m Bool)
-> (RetryStatus -> m b)
-> m b
retrying :: RetryPolicyM m
-> (RetryStatus -> b -> m Bool) -> (RetryStatus -> m b) -> m b
retrying = RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m Bool)
-> (RetryStatus -> m b)
-> m b
forall (m :: * -> *) b.
MonadIO m =>
RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m Bool)
-> (RetryStatus -> m b)
-> m b
resumeRetrying RetryStatus
defaultRetryStatus
resumeRetrying
:: MonadIO m
=> RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m Bool)
-> (RetryStatus -> m b)
-> m b
resumeRetrying :: RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m Bool)
-> (RetryStatus -> m b)
-> m b
resumeRetrying RetryStatus
retryStatus RetryPolicyM m
policy RetryStatus -> b -> m Bool
chk RetryStatus -> m b
f =
RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m RetryAction)
-> (RetryStatus -> m b)
-> m b
forall (m :: * -> *) b.
MonadIO m =>
RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m RetryAction)
-> (RetryStatus -> m b)
-> m b
resumeRetryingDynamic
RetryStatus
retryStatus
RetryPolicyM m
policy
(\RetryStatus
rs -> (Bool -> RetryAction) -> m Bool -> m RetryAction
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Bool -> RetryAction
toRetryAction (m Bool -> m RetryAction) -> (b -> m Bool) -> b -> m RetryAction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RetryStatus -> b -> m Bool
chk RetryStatus
rs)
RetryStatus -> m b
f
retryingDynamic
:: MonadIO m
=> RetryPolicyM m
-> (RetryStatus -> b -> m RetryAction)
-> (RetryStatus -> m b)
-> m b
retryingDynamic :: RetryPolicyM m
-> (RetryStatus -> b -> m RetryAction)
-> (RetryStatus -> m b)
-> m b
retryingDynamic = RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m RetryAction)
-> (RetryStatus -> m b)
-> m b
forall (m :: * -> *) b.
MonadIO m =>
RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m RetryAction)
-> (RetryStatus -> m b)
-> m b
resumeRetryingDynamic RetryStatus
defaultRetryStatus
resumeRetryingDynamic
:: MonadIO m
=> RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m RetryAction)
-> (RetryStatus -> m b)
-> m b
resumeRetryingDynamic :: RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> b -> m RetryAction)
-> (RetryStatus -> m b)
-> m b
resumeRetryingDynamic RetryStatus
retryStatus RetryPolicyM m
policy RetryStatus -> b -> m RetryAction
chk RetryStatus -> m b
f = RetryStatus -> m b
go RetryStatus
retryStatus
where
go :: RetryStatus -> m b
go RetryStatus
s = do
b
res <- RetryStatus -> m b
f RetryStatus
s
let consultPolicy :: RetryPolicyM m -> m b
consultPolicy RetryPolicyM m
policy' = do
Maybe RetryStatus
rs <- RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
forall (m :: * -> *).
MonadIO m =>
RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
applyAndDelay RetryPolicyM m
policy' RetryStatus
s
case Maybe RetryStatus
rs of
Maybe RetryStatus
Nothing -> b -> m b
forall (m :: * -> *) a. Monad m => a -> m a
return b
res
Just RetryStatus
rs' -> RetryStatus -> m b
go (RetryStatus -> m b) -> RetryStatus -> m b
forall a b. (a -> b) -> a -> b
$! RetryStatus
rs'
RetryAction
chk' <- RetryStatus -> b -> m RetryAction
chk RetryStatus
s b
res
case RetryAction
chk' of
RetryAction
DontRetry -> b -> m b
forall (m :: * -> *) a. Monad m => a -> m a
return b
res
RetryAction
ConsultPolicy -> RetryPolicyM m -> m b
consultPolicy RetryPolicyM m
policy
ConsultPolicyOverrideDelay Int
delay ->
RetryPolicyM m -> m b
consultPolicy (RetryPolicyM m -> m b) -> RetryPolicyM m -> m b
forall a b. (a -> b) -> a -> b
$ (Int -> Int) -> RetryPolicyM m -> RetryPolicyM m
forall (m :: * -> *).
Functor m =>
(Int -> Int) -> RetryPolicyM m -> RetryPolicyM m
modifyRetryPolicyDelay (Int -> Int -> Int
forall a b. a -> b -> a
const Int
delay) RetryPolicyM m
policy
recoverAll
#if MIN_VERSION_exceptions(0, 6, 0)
:: (MonadIO m, MonadMask m)
#else
:: (MonadIO m, MonadCatch m)
#endif
=> RetryPolicyM m
-> (RetryStatus -> m a)
-> m a
recoverAll :: RetryPolicyM m -> (RetryStatus -> m a) -> m a
recoverAll = RetryStatus -> RetryPolicyM m -> (RetryStatus -> m a) -> m a
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
RetryStatus -> RetryPolicyM m -> (RetryStatus -> m a) -> m a
resumeRecoverAll RetryStatus
defaultRetryStatus
resumeRecoverAll
#if MIN_VERSION_exceptions(0, 6, 0)
:: (MonadIO m, MonadMask m)
#else
:: (MonadIO m, MonadCatch m)
#endif
=> RetryStatus
-> RetryPolicyM m
-> (RetryStatus -> m a)
-> m a
resumeRecoverAll :: RetryStatus -> RetryPolicyM m -> (RetryStatus -> m a) -> m a
resumeRecoverAll RetryStatus
retryStatus RetryPolicyM m
set RetryStatus -> m a
f = RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m Bool]
-> (RetryStatus -> m a)
-> m a
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m Bool]
-> (RetryStatus -> m a)
-> m a
resumeRecovering RetryStatus
retryStatus RetryPolicyM m
set [RetryStatus -> Handler m Bool]
handlers RetryStatus -> m a
f
where
handlers :: [RetryStatus -> Handler m Bool]
handlers = [RetryStatus -> Handler m Bool]
forall (m :: * -> *). MonadIO m => [RetryStatus -> Handler m Bool]
skipAsyncExceptions [RetryStatus -> Handler m Bool]
-> [RetryStatus -> Handler m Bool]
-> [RetryStatus -> Handler m Bool]
forall a. [a] -> [a] -> [a]
++ [RetryStatus -> Handler m Bool
forall (m :: * -> *) p. Monad m => p -> Handler m Bool
h]
h :: p -> Handler m Bool
h p
_ = (SomeException -> m Bool) -> Handler m Bool
forall (m :: * -> *) a e. Exception e => (e -> m a) -> Handler m a
Handler ((SomeException -> m Bool) -> Handler m Bool)
-> (SomeException -> m Bool) -> Handler m Bool
forall a b. (a -> b) -> a -> b
$ \ (SomeException
_ :: SomeException) -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
skipAsyncExceptions
:: ( MonadIO m
)
=> [RetryStatus -> Handler m Bool]
skipAsyncExceptions :: [RetryStatus -> Handler m Bool]
skipAsyncExceptions = [RetryStatus -> Handler m Bool]
forall p. [p -> Handler m Bool]
handlers
where
asyncH :: p -> Handler m Bool
asyncH p
_ = (AsyncException -> m Bool) -> Handler m Bool
forall (m :: * -> *) a e. Exception e => (e -> m a) -> Handler m a
Handler ((AsyncException -> m Bool) -> Handler m Bool)
-> (AsyncException -> m Bool) -> Handler m Bool
forall a b. (a -> b) -> a -> b
$ \ (AsyncException
_ :: AsyncException) -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
#if MIN_VERSION_base(4, 7, 0)
someAsyncH :: p -> Handler m Bool
someAsyncH p
_ = (SomeAsyncException -> m Bool) -> Handler m Bool
forall (m :: * -> *) a e. Exception e => (e -> m a) -> Handler m a
Handler ((SomeAsyncException -> m Bool) -> Handler m Bool)
-> (SomeAsyncException -> m Bool) -> Handler m Bool
forall a b. (a -> b) -> a -> b
$ \(SomeAsyncException
_ :: SomeAsyncException) -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
handlers :: [p -> Handler m Bool]
handlers = [p -> Handler m Bool
forall (m :: * -> *) p. Monad m => p -> Handler m Bool
asyncH, p -> Handler m Bool
forall (m :: * -> *) p. Monad m => p -> Handler m Bool
someAsyncH]
#else
handlers = [asyncH]
#endif
recovering
#if MIN_VERSION_exceptions(0, 6, 0)
:: (MonadIO m, MonadMask m)
#else
:: (MonadIO m, MonadCatch m)
#endif
=> RetryPolicyM m
-> [RetryStatus -> Handler m Bool]
-> (RetryStatus -> m a)
-> m a
recovering :: RetryPolicyM m
-> [RetryStatus -> Handler m Bool] -> (RetryStatus -> m a) -> m a
recovering = RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m Bool]
-> (RetryStatus -> m a)
-> m a
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m Bool]
-> (RetryStatus -> m a)
-> m a
resumeRecovering RetryStatus
defaultRetryStatus
resumeRecovering
#if MIN_VERSION_exceptions(0, 6, 0)
:: (MonadIO m, MonadMask m)
#else
:: (MonadIO m, MonadCatch m)
#endif
=> RetryStatus
-> RetryPolicyM m
-> [(RetryStatus -> Handler m Bool)]
-> (RetryStatus -> m a)
-> m a
resumeRecovering :: RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m Bool]
-> (RetryStatus -> m a)
-> m a
resumeRecovering RetryStatus
retryStatus RetryPolicyM m
policy [RetryStatus -> Handler m Bool]
hs RetryStatus -> m a
f =
RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m RetryAction]
-> (RetryStatus -> m a)
-> m a
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m RetryAction]
-> (RetryStatus -> m a)
-> m a
resumeRecoveringDynamic RetryStatus
retryStatus RetryPolicyM m
policy [RetryStatus -> Handler m RetryAction]
hs' RetryStatus -> m a
f
where
hs' :: [RetryStatus -> Handler m RetryAction]
hs' = ((RetryStatus -> Handler m Bool)
-> RetryStatus -> Handler m RetryAction)
-> [RetryStatus -> Handler m Bool]
-> [RetryStatus -> Handler m RetryAction]
forall a b. (a -> b) -> [a] -> [b]
map ((Bool -> RetryAction) -> Handler m Bool -> Handler m RetryAction
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Bool -> RetryAction
toRetryAction (Handler m Bool -> Handler m RetryAction)
-> (RetryStatus -> Handler m Bool)
-> RetryStatus
-> Handler m RetryAction
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) [RetryStatus -> Handler m Bool]
hs
recoveringDynamic
#if MIN_VERSION_exceptions(0, 6, 0)
:: (MonadIO m, MonadMask m)
#else
:: (MonadIO m, MonadCatch m)
#endif
=> RetryPolicyM m
-> [RetryStatus -> Handler m RetryAction]
-> (RetryStatus -> m a)
-> m a
recoveringDynamic :: RetryPolicyM m
-> [RetryStatus -> Handler m RetryAction]
-> (RetryStatus -> m a)
-> m a
recoveringDynamic = RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m RetryAction]
-> (RetryStatus -> m a)
-> m a
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m RetryAction]
-> (RetryStatus -> m a)
-> m a
resumeRecoveringDynamic RetryStatus
defaultRetryStatus
resumeRecoveringDynamic
#if MIN_VERSION_exceptions(0, 6, 0)
:: (MonadIO m, MonadMask m)
#else
:: (MonadIO m, MonadCatch m)
#endif
=> RetryStatus
-> RetryPolicyM m
-> [(RetryStatus -> Handler m RetryAction)]
-> (RetryStatus -> m a)
-> m a
resumeRecoveringDynamic :: RetryStatus
-> RetryPolicyM m
-> [RetryStatus -> Handler m RetryAction]
-> (RetryStatus -> m a)
-> m a
resumeRecoveringDynamic RetryStatus
retryStatus RetryPolicyM m
policy [RetryStatus -> Handler m RetryAction]
hs RetryStatus -> m a
f = ((forall a. m a -> m a) -> m a) -> m a
forall (m :: * -> *) b.
MonadMask m =>
((forall a. m a -> m a) -> m b) -> m b
mask (((forall a. m a -> m a) -> m a) -> m a)
-> ((forall a. m a -> m a) -> m a) -> m a
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> m a
restore -> (m a -> m a) -> RetryStatus -> m a
forall b. (m a -> m b) -> RetryStatus -> m b
go m a -> m a
forall a. m a -> m a
restore RetryStatus
retryStatus
where
go :: (m a -> m b) -> RetryStatus -> m b
go m a -> m b
restore = RetryStatus -> m b
loop
where
loop :: RetryStatus -> m b
loop RetryStatus
s = do
Either SomeException b
r <- m b -> m (Either SomeException b)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> m (Either e a)
try (m b -> m (Either SomeException b))
-> m b -> m (Either SomeException b)
forall a b. (a -> b) -> a -> b
$ m a -> m b
restore (RetryStatus -> m a
f RetryStatus
s)
case Either SomeException b
r of
Right b
x -> b -> m b
forall (m :: * -> *) a. Monad m => a -> m a
return b
x
Left SomeException
e -> SomeException -> [RetryStatus -> Handler m RetryAction] -> m b
recover (SomeException
e :: SomeException) [RetryStatus -> Handler m RetryAction]
hs
where
recover :: SomeException -> [RetryStatus -> Handler m RetryAction] -> m b
recover SomeException
e [] = SomeException -> m b
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SomeException
e
recover SomeException
e ((((RetryStatus -> Handler m RetryAction)
-> RetryStatus -> Handler m RetryAction
forall a b. (a -> b) -> a -> b
$ RetryStatus
s) -> Handler e -> m RetryAction
h) : [RetryStatus -> Handler m RetryAction]
hs')
| Just e
e' <- SomeException -> Maybe e
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = do
let consultPolicy :: RetryPolicyM m -> m b
consultPolicy RetryPolicyM m
policy' = do
Maybe RetryStatus
rs <- RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
forall (m :: * -> *).
MonadIO m =>
RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
applyAndDelay RetryPolicyM m
policy' RetryStatus
s
case Maybe RetryStatus
rs of
Just RetryStatus
rs' -> RetryStatus -> m b
loop (RetryStatus -> m b) -> RetryStatus -> m b
forall a b. (a -> b) -> a -> b
$! RetryStatus
rs'
Maybe RetryStatus
Nothing -> e -> m b
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM e
e'
RetryAction
chk <- e -> m RetryAction
h e
e'
case RetryAction
chk of
RetryAction
DontRetry -> e -> m b
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM e
e'
RetryAction
ConsultPolicy -> RetryPolicyM m -> m b
consultPolicy RetryPolicyM m
policy
ConsultPolicyOverrideDelay delay ->
RetryPolicyM m -> m b
consultPolicy (RetryPolicyM m -> m b) -> RetryPolicyM m -> m b
forall a b. (a -> b) -> a -> b
$ (Int -> Int) -> RetryPolicyM m -> RetryPolicyM m
forall (m :: * -> *).
Functor m =>
(Int -> Int) -> RetryPolicyM m -> RetryPolicyM m
modifyRetryPolicyDelay (Int -> Int -> Int
forall a b. a -> b -> a
const Int
delay) RetryPolicyM m
policy
| Bool
otherwise = SomeException -> [RetryStatus -> Handler m RetryAction] -> m b
recover SomeException
e [RetryStatus -> Handler m RetryAction]
hs'
stepping
#if MIN_VERSION_exceptions(0, 6, 0)
:: (MonadIO m, MonadMask m)
#else
:: (MonadIO m, MonadCatch m)
#endif
=> RetryPolicyM m
-> [RetryStatus -> Handler m Bool]
-> (RetryStatus -> m ())
-> (RetryStatus -> m a)
-> RetryStatus
-> m (Maybe a)
stepping :: RetryPolicyM m
-> [RetryStatus -> Handler m Bool]
-> (RetryStatus -> m ())
-> (RetryStatus -> m a)
-> RetryStatus
-> m (Maybe a)
stepping RetryPolicyM m
policy [RetryStatus -> Handler m Bool]
hs RetryStatus -> m ()
schedule RetryStatus -> m a
f RetryStatus
s = do
Either SomeException a
r <- m a -> m (Either SomeException a)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> m (Either e a)
try (m a -> m (Either SomeException a))
-> m a -> m (Either SomeException a)
forall a b. (a -> b) -> a -> b
$ RetryStatus -> m a
f RetryStatus
s
case Either SomeException a
r of
Right a
x -> Maybe a -> m (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a -> m (Maybe a)) -> Maybe a -> m (Maybe a)
forall a b. (a -> b) -> a -> b
$ a -> Maybe a
forall a. a -> Maybe a
Just a
x
Left SomeException
e -> SomeException -> [RetryStatus -> Handler m Bool] -> m (Maybe a)
forall a.
SomeException -> [RetryStatus -> Handler m Bool] -> m (Maybe a)
recover (SomeException
e :: SomeException) [RetryStatus -> Handler m Bool]
hs
where
recover :: SomeException -> [RetryStatus -> Handler m Bool] -> m (Maybe a)
recover SomeException
e [] = SomeException -> m (Maybe a)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SomeException
e
recover SomeException
e ((((RetryStatus -> Handler m Bool) -> RetryStatus -> Handler m Bool
forall a b. (a -> b) -> a -> b
$ RetryStatus
s) -> Handler e -> m Bool
h) : [RetryStatus -> Handler m Bool]
hs')
| Just e
e' <- SomeException -> Maybe e
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e = do
Bool
chk <- e -> m Bool
h e
e'
case Bool
chk of
Bool
True -> do
Maybe RetryStatus
res <- RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
forall (m :: * -> *).
Monad m =>
RetryPolicyM m -> RetryStatus -> m (Maybe RetryStatus)
applyPolicy RetryPolicyM m
policy RetryStatus
s
case Maybe RetryStatus
res of
Just RetryStatus
rs -> do
RetryStatus -> m ()
schedule (RetryStatus -> m ()) -> RetryStatus -> m ()
forall a b. (a -> b) -> a -> b
$! RetryStatus
rs
Maybe a -> m (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing
Maybe RetryStatus
Nothing -> e -> m (Maybe a)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM e
e'
Bool
False -> e -> m (Maybe a)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM e
e'
| Bool
otherwise = SomeException -> [RetryStatus -> Handler m Bool] -> m (Maybe a)
recover SomeException
e [RetryStatus -> Handler m Bool]
hs'
logRetries
:: ( Monad m
, Exception e)
=> (e -> m Bool)
-> (Bool -> e -> RetryStatus -> m ())
-> RetryStatus
-> Handler m Bool
logRetries :: (e -> m Bool)
-> (Bool -> e -> RetryStatus -> m ())
-> RetryStatus
-> Handler m Bool
logRetries e -> m Bool
test Bool -> e -> RetryStatus -> m ()
reporter RetryStatus
status = (e -> m Bool) -> Handler m Bool
forall (m :: * -> *) a e. Exception e => (e -> m a) -> Handler m a
Handler ((e -> m Bool) -> Handler m Bool)
-> (e -> m Bool) -> Handler m Bool
forall a b. (a -> b) -> a -> b
$ \ e
err -> do
Bool
result <- e -> m Bool
test e
err
Bool -> e -> RetryStatus -> m ()
reporter Bool
result e
err RetryStatus
status
Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
result
defaultLogMsg :: (Exception e) => Bool -> e -> RetryStatus -> String
defaultLogMsg :: Bool -> e -> RetryStatus -> String
defaultLogMsg Bool
shouldRetry e
err RetryStatus
status =
String
"[retry:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
iter String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"] Encountered " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> e -> String
forall a. Show a => a -> String
show e
err String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
". " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
nextMsg
where
iter :: String
iter = Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ RetryStatus -> Int
rsIterNumber RetryStatus
status
nextMsg :: String
nextMsg = if Bool
shouldRetry then String
"Retrying." else String
"Crashing."
simulatePolicy :: Monad m => Int -> RetryPolicyM m -> m [(Int, Maybe Int)]
simulatePolicy :: Int -> RetryPolicyM m -> m [(Int, Maybe Int)]
simulatePolicy Int
n (RetryPolicyM RetryStatus -> m (Maybe Int)
f) = (StateT RetryStatus m [(Int, Maybe Int)]
-> RetryStatus -> m [(Int, Maybe Int)])
-> RetryStatus
-> StateT RetryStatus m [(Int, Maybe Int)]
-> m [(Int, Maybe Int)]
forall a b c. (a -> b -> c) -> b -> a -> c
flip StateT RetryStatus m [(Int, Maybe Int)]
-> RetryStatus -> m [(Int, Maybe Int)]
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
evalStateT RetryStatus
defaultRetryStatus (StateT RetryStatus m [(Int, Maybe Int)] -> m [(Int, Maybe Int)])
-> StateT RetryStatus m [(Int, Maybe Int)] -> m [(Int, Maybe Int)]
forall a b. (a -> b) -> a -> b
$ [Int]
-> (Int -> StateT RetryStatus m (Int, Maybe Int))
-> StateT RetryStatus m [(Int, Maybe Int)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [Int
0..Int
n] ((Int -> StateT RetryStatus m (Int, Maybe Int))
-> StateT RetryStatus m [(Int, Maybe Int)])
-> (Int -> StateT RetryStatus m (Int, Maybe Int))
-> StateT RetryStatus m [(Int, Maybe Int)]
forall a b. (a -> b) -> a -> b
$ \Int
i -> do
RetryStatus
stat <- StateT RetryStatus m RetryStatus
forall (m :: * -> *) s. Monad m => StateT s m s
get
Maybe Int
delay <- m (Maybe Int) -> StateT RetryStatus m (Maybe Int)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (RetryStatus -> m (Maybe Int)
f RetryStatus
stat)
RetryStatus -> StateT RetryStatus m ()
forall (m :: * -> *) s. Monad m => s -> StateT s m ()
put (RetryStatus -> StateT RetryStatus m ())
-> RetryStatus -> StateT RetryStatus m ()
forall a b. (a -> b) -> a -> b
$! RetryStatus
stat
{ rsIterNumber :: Int
rsIterNumber = Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
, rsCumulativeDelay :: Int
rsCumulativeDelay = RetryStatus -> Int
rsCumulativeDelay RetryStatus
stat Int -> Int -> Int
`boundedPlus` Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
0 Maybe Int
delay
, rsPreviousDelay :: Maybe Int
rsPreviousDelay = Maybe Int
delay
}
(Int, Maybe Int) -> StateT RetryStatus m (Int, Maybe Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
i, Maybe Int
delay)
simulatePolicyPP :: Int -> RetryPolicyM IO -> IO ()
simulatePolicyPP :: Int -> RetryPolicyM IO -> IO ()
simulatePolicyPP Int
n RetryPolicyM IO
p = do
[(Int, Maybe Int)]
ps <- Int -> RetryPolicyM IO -> IO [(Int, Maybe Int)]
forall (m :: * -> *).
Monad m =>
Int -> RetryPolicyM m -> m [(Int, Maybe Int)]
simulatePolicy Int
n RetryPolicyM IO
p
[(Int, Maybe Int)] -> ((Int, Maybe Int) -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(Int, Maybe Int)]
ps (((Int, Maybe Int) -> IO ()) -> IO ())
-> ((Int, Maybe Int) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ (Int
iterNo, Maybe Int
res) -> String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
Int -> String
forall a. Show a => a -> String
show Int
iterNo String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
": " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String -> (Int -> String) -> Maybe Int -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"Inhibit" Int -> String
forall a. (Integral a, Show a) => a -> String
ppTime Maybe Int
res
String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Total cumulative delay would be: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<>
Int -> String
forall a. (Integral a, Show a) => a -> String
ppTime ([Int] -> Int
boundedSum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ ((Int, Maybe Int) -> Maybe Int) -> [(Int, Maybe Int)] -> [Int]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (Int, Maybe Int) -> Maybe Int
forall a b. (a, b) -> b
snd [(Int, Maybe Int)]
ps)
ppTime :: (Integral a, Show a) => a -> String
ppTime :: a -> String
ppTime a
n | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000 = a -> String
forall a. Show a => a -> String
show a
n String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"us"
| a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000000 = Double -> String
forall a. Show a => a -> String
show ((a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1000) :: Double) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"ms"
| Bool
otherwise = Double -> String
forall a. Show a => a -> String
show ((a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1000) :: Double) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"ms"
boundedPlus :: Int -> Int -> Int
boundedPlus :: Int -> Int -> Int
boundedPlus i :: Int
i@(I# Int#
i#) j :: Int
j@(I# Int#
j#) = case Int# -> Int# -> (# Int#, Int# #)
addIntC# Int#
i# Int#
j# of
(# Int#
k#, Int#
0# #) -> Int# -> Int
I# Int#
k#
(# Int#
_, Int#
_ #)
| (Int -> Int) -> Int -> Int -> Int
forall a p. Ord a => (p -> a) -> p -> p -> p
maxBy Int -> Int
forall a. Num a => a -> a
abs Int
i Int
j Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 -> Int
forall a. Bounded a => a
minBound
| Bool
otherwise -> Int
forall a. Bounded a => a
maxBound
where
maxBy :: (p -> a) -> p -> p -> p
maxBy p -> a
f p
a p
b = if p -> a
f p
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= p -> a
f p
b then p
a else p
b
boundedMult :: Int -> Int -> Int
boundedMult :: Int -> Int -> Int
boundedMult i :: Int
i@(I# Int#
i#) j :: Int
j@(I# Int#
j#) = case Int# -> Int# -> Int#
mulIntMayOflo# Int#
i# Int#
j# of
Int#
0# -> Int# -> Int
I# (Int#
i# Int# -> Int# -> Int#
*# Int#
j#)
Int#
_ | Int -> Int
forall a. Num a => a -> a
signum Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int -> Int
forall a. Num a => a -> a
signum Int
j Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 -> Int
forall a. Bounded a => a
minBound
| Bool
otherwise -> Int
forall a. Bounded a => a
maxBound
boundedSum :: [Int] -> Int
boundedSum :: [Int] -> Int
boundedSum = (Int -> Int -> Int) -> Int -> [Int] -> Int
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Int -> Int -> Int
boundedPlus Int
0
boundedPow :: Int -> Int -> Int
boundedPow :: Int -> Int -> Int
boundedPow Int
x0 Int
y0
| Int
y0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = String -> Int
forall a. HasCallStack => String -> a
error String
"Negative exponent"
| Int
y0 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Int
1
| Bool
otherwise = Int -> Int -> Int
forall a. Integral a => Int -> a -> Int
f Int
x0 Int
y0
where
f :: Int -> a -> Int
f Int
x a
y
| a -> Bool
forall a. Integral a => a -> Bool
even a
y = Int -> a -> Int
f (Int
x Int -> Int -> Int
`boundedMult` Int
x) (a
y a -> a -> a
forall a. Integral a => a -> a -> a
`quot` a
2)
| a
y a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
1 = Int
x
| Bool
otherwise = Int -> a -> Int -> Int
forall a. Integral a => Int -> a -> Int -> Int
g (Int
x Int -> Int -> Int
`boundedMult` Int
x) ((a
y a -> a -> a
forall a. Num a => a -> a -> a
- a
1) a -> a -> a
forall a. Integral a => a -> a -> a
`quot` a
2) Int
x
g :: Int -> a -> Int -> Int
g Int
x a
y Int
z
| a -> Bool
forall a. Integral a => a -> Bool
even a
y = Int -> a -> Int -> Int
g (Int
x Int -> Int -> Int
`boundedMult` Int
x) (a
y a -> a -> a
forall a. Integral a => a -> a -> a
`quot` a
2) Int
z
| a
y a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
1 = Int
x Int -> Int -> Int
`boundedMult` Int
z
| Bool
otherwise = Int -> a -> Int -> Int
g (Int
x Int -> Int -> Int
`boundedMult` Int
x) ((a
y a -> a -> a
forall a. Num a => a -> a -> a
- a
1) a -> a -> a
forall a. Integral a => a -> a -> a
`quot` a
2) (Int
x Int -> Int -> Int
`boundedMult` Int
z)
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
type Lens' s a = Lens s s a a
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
lens s -> a
sa s -> b -> t
sbt a -> f b
afb s
s = s -> b -> t
sbt s
s (b -> t) -> f b -> f t
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> f b
afb (s -> a
sa s
s)
{-# INLINE lens #-}