DarkHorse1997
DarkHorse1997

Reputation: 103

How can I create a thread in Haskell that will restart if it gets killed due to any reason?

First some background, I have a requirement where I need to have a config that needs to be updated(by fetching from a Database or an API call) every 10 mins(for example a session token which expires every 10 mins) and it needs to be available to my web server app.

The solution I came up for this is to create a separate long-running thread which will keep on refreshing the config every 10 mins. I will create this thread during application start and need this thread to keep on running as long as the application is running. If this thread gets killed due to some exception, I need to automatically restart it so that it can keep in doing its job.

I tried using try to handle any exceptions that might be thrown when my thread is killed, but it doesn't seem to detect or catch the exception.

Code I used:

restartableThread :: IO () -> IO ()
restartableThread action = do
  result <- try (forkIO action)
  case result of
    Left (e :: SomeException) -> do
      putStrLn $ "Thread killed due to: " ++ show e
      -- Restart the thread after a delay
      threadDelay 1000000  -- 1 second delay
      restartableThread action
    Right _ -> return ()

Is there any other way to make sure my thread doesn't get killed, and if it gets killed, it is restarted automatically?

I'm also open to other ideas for tackling this requirement.

Upvotes: 1

Views: 103

Answers (1)

Li-yao Xia
Li-yao Xia

Reputation: 33569

Use try action to catch exceptions thrown by action.

try (forkIO action) does not handle exceptions from the action, only exceptions from forking the action, which practically never happen.

This function forks a thread that repeats an action every 10 minutes, or retries with a short delay when the action fails.

startBgJob :: IO () -> IO ()
startBgJob = void (forkIO (forever (threadDelay tenminutes >> retry action)))
  where
    retry action = do
      e <- try action
      case e of
        Left (_ :: SomeException) -> threadDelay onesecond >> retry action
        Right () -> pure ()
    tenminutes = 600 * onesecond
    onesecond = 1000000

Upvotes: 0

Related Questions