3

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.

bbarker
  • 11,636
  • 9
  • 38
  • 62

1 Answers1

5

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
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 1
    FWIW, I was able to use the same `catchAny` - all I had to change was adding in the recursive call to `retryForever`, which I stupidly forgot, somehow thinking that `catchAll` was handling the recursion for me. – bbarker Aug 23 '19 at 21:42
  • 1
    @bbarker: the difference seems to be that `catchAny` catches all *synchronous* errors, whereas `catchAll` catches all exceptions. Although they both probably will do the job :) – Willem Van Onsem Aug 23 '19 at 21:49
  • 1
    At least, I guess `retryForever` should work if I remember to call it on the "main loop" of each thread. – bbarker Aug 23 '19 at 22:27
  • @bbarker: yes, probably there will be no difference in that case. So I guess you can use both :). – Willem Van Onsem Aug 24 '19 at 11:36