Safe Haskell | None |
---|---|
Language | Haskell2010 |
Control.Monad.Trans.Fault
Contents
Description
monad-fault
provides an extensible way to trigger arbitrary
failures within your programs. Potential faults are tracked in the
type system via MonadFault
constraints. Useful for testing fault tolerance
(e.g. retry logic)
For instance:
mightFault :: (MonadIO
m,MonadFaults
'["redis", "s3", "sqs"] m) => Redis.Connection -> AWS.Env -> m () mightFault redisConn awsEnv = do s3Result <-faulty
"s3" $ readFromS3 awsEnv
"redis" $ writeToRedis redisConn s3Resultfaulty
faulty
@"sqs" $ writeToSQS awsEnv s3Result
In production, we'd run this with FaultlessT
which will
cause the faults to be elided:
runFaultlessT (mightFault redisConn awsEnv) :: IO ()
But while testing, we can create a FaultController
and run with FaultyT
. In our tests, we can set different
parts of the program to fault using setFault
& resetFault
.
We can then confirm, for instance, that a Redis blip followed
by a retry still results in the correct effects being performed
on the world:
fc <-newFaultController
'["redis", "s3", "sqs"]
"redis" fc (redisException "uh oh!")setFault
runFaultyT
fc (mightFault redisConn awsEnv)shouldThrow
anyExceptionresetFault
@"redis" fcrunFaultyT
fc (mightFault redisConn awsEnv) performChecks
- fault :: forall fault m. MonadFault fault m => m ()
- faulty :: forall fault m a. MonadFault fault m => m a -> m a
- class Monad m => MonadFault fault m where
- type family MonadFaults (faults :: [Symbol]) (m :: * -> *) :: Constraint where ...
- newtype FaultlessT m a = FaultlessT {
- unFaultlessT :: IdentityT m a
- runFaultlessT :: FaultlessT m a -> m a
- newtype FaultyT faults m a = FaultyT {
- unFaultyT :: ReaderT (FaultController faults) m a
- runFaultyT :: FaultController faults -> FaultyT faults m a -> m a
- newFaultController :: NewFault faults => IO (FaultController faults)
- setFault :: forall fault faults e. (HasFault fault faults, Exception e) => e -> FaultController faults -> IO ()
- resetFault :: forall fault faults e. (HasFault fault faults, Exception e) => FaultController faults -> IO ()
- printFaultController :: FaultController faults -> IO ()
- showFaultController :: FaultController faults -> IO String
- askFaultController :: Monad m => FaultyT faults m (FaultController faults)
- data FaultController faults where
- FCNil :: FaultController '[]
- FCCons :: forall f rest. KnownSymbol f => Proxy f -> !(IORef FaultConfig) -> FaultController rest -> FaultController (f ': rest)
- data FaultConfig = FaultConfig (Maybe SomeException)
- class NewFault faults where
- class HasFault f faults where
Causing faults
fault :: forall fault m. MonadFault fault m => m () Source #
Cause a fault named fault
Meant to be used w/TypeApplications
>>>
fault @"redis" :: MonadFault "redis" m => m ()
faulty :: forall fault m a. MonadFault fault m => m a -> m a Source #
Tag an action as a potential fault named fault
>>>
faulty @"failure name" $ mightFail
The MonadFault Class
class Monad m => MonadFault fault m where Source #
m
is capable of having fault
. fault
s are
named with type-level strings
Minimal complete definition
Instances
Monad m => MonadFault fault (FaultlessT m) Source # | |
(Monad (t m), MonadTrans t, MonadFault fault m) => MonadFault fault (t m) Source # | Automatic instances for MonadTrans |
(MonadIO m, HasFault f faults) => MonadFault f (FaultyT faults m) Source # | |
type family MonadFaults (faults :: [Symbol]) (m :: * -> *) :: Constraint where ... Source #
One m
frequently has many potential faults
Equations
MonadFaults '[] m = () | |
MonadFaults (fault ': rest) m = (MonadFault fault m, MonadFaults rest m) |
The FaultlessT & FaultyT monad transformers
newtype FaultlessT m a Source #
Can never fault.
Constructors
FaultlessT | |
Fields
|
Instances
MonadTrans FaultlessT Source # | |
MonadTransControl FaultlessT Source # | |
MonadBaseControl b m => MonadBaseControl b (FaultlessT m) Source # | |
MonadBase b m => MonadBase b (FaultlessT m) Source # | |
MonadError e m => MonadError e (FaultlessT m) Source # | |
MonadReader r m => MonadReader r (FaultlessT m) Source # | |
MonadState s m => MonadState s (FaultlessT m) Source # | |
Monad m => MonadFault fault (FaultlessT m) Source # | |
Monad m => Monad (FaultlessT m) Source # | |
Functor m => Functor (FaultlessT m) Source # | |
Applicative m => Applicative (FaultlessT m) Source # | |
MonadIO m => MonadIO (FaultlessT m) Source # | |
MonadThrow m => MonadThrow (FaultlessT m) Source # | |
MonadCatch m => MonadCatch (FaultlessT m) Source # | |
MonadLogger m => MonadLogger (FaultlessT m) Source # | |
MonadResource m => MonadResource (FaultlessT m) Source # | |
type StT FaultlessT a Source # | |
type StM (FaultlessT m) a Source # | |
runFaultlessT :: FaultlessT m a -> m a Source #
Unwrap FaultlessT
, ignoring all possible faults
newtype FaultyT faults m a Source #
Monad transformer that allows the caller to control which faults occur
Constructors
FaultyT | |
Fields
|
Instances
runFaultyT :: FaultController faults -> FaultyT faults m a -> m a Source #
Run a FaultyT
, causing faults along the way according to
the given FaultController
Controlling faults
newFaultController :: NewFault faults => IO (FaultController faults) Source #
Create a FaultController
initially configured to never fault
setFault :: forall fault faults e. (HasFault fault faults, Exception e) => e -> FaultController faults -> IO () Source #
Set a fault
to throw a given Exception
resetFault :: forall fault faults e. (HasFault fault faults, Exception e) => FaultController faults -> IO () Source #
Set a fault
to not fail.
Debugging
printFaultController :: FaultController faults -> IO () Source #
>>>
fc <- newFaultController @'["x", "y"]
>>>
printFaultController fc
(FCCons @"x" FaultConfig Nothing (FCCons @"y" FaultConfig Nothing FCNil))
showFaultController :: FaultController faults -> IO String Source #
Create the output of printFaultController
askFaultController :: Monad m => FaultyT faults m (FaultController faults) Source #
Access the FaultController
within a FaultyT
. You
usually can't use this because you'll write your programs
in terms of MonadFault "whatever" m =>
Internals
data FaultController faults where Source #
Extensible record of FaultConfigs, each tagged with a fault name at the type level
Constructors
FCNil :: FaultController '[] | |
FCCons :: forall f rest. KnownSymbol f => Proxy f -> !(IORef FaultConfig) -> FaultController rest -> FaultController (f ': rest) |
data FaultConfig Source #
If the exception is Just
, we fault. Otherwise, we don't
Constructors
FaultConfig (Maybe SomeException) |
Instances
class NewFault faults where Source #
Create a default, non-faulting FaultController
Minimal complete definition
Methods
newFaultController :: IO (FaultController faults) Source #
Create a FaultController
initially configured to never fault
class HasFault f faults where Source #
Query & modify a FaultController
at certain faults
Minimal complete definition
Methods
getFaultConfig :: FaultController faults -> IO FaultConfig Source #
setFaultConfig :: FaultConfig -> FaultController faults -> IO () Source #