How to write a "retryForever" function in Haskell using exception handling?

163 Views Asked by At

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.

1

There are 1 best solutions below

4
willeM_ Van Onsem On BEST ANSWER

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