I'd like to create a function that can recover from as many errors as is reasonable, and try again. Of course, meaningful handling of errors is covered in other parts of the program - this is a last ditch effort to keep things running. So I wrote this:
retryForever prog = catchAny prog progRetry
where
progRetry :: SomeException -> m a
progRetry ex = do
putStrLn $ pack $ show ex
threadDelay 4000
prog
Then I wrap my main IO action in retryForever
:
main :: IO ()
main = retryForever $ do
logger <- newLogger
-- ...
In another part of my program (likely a different green thread), I test this with:
error "this is a TEST ERROR"
Resulting in:
: this is a TEST ERROR
CallStack (from HasCallStack):
error, called at XXXX
(and the program dies instead of continuing on)
Note that I'm using classy-prelude, for the cases where that may matter, e.g. catchAny
doesn't handle asynchronous exceptions in there, which may well be the issue here.
When the program failed, you should run the program prog
again, but wrapped in retryForever
such that if it fails again, you thus keep trying:
import Control.Monad.Catch(catchAll)
retryForever :: IO a -> IO a
retryForever prog = catchAll prog retry
where retry ex = do
putStrLn $ pack $ show ex
threadDelay 4000
retryForever prog