Bercovici Adrian
Bercovici Adrian

Reputation: 9370

How to retry blocking IO Action when timeout?

How does one deal with a blocking IO action in Haskell? How can I put this IO action inside a scope and manage this scope from another method? If the timeout is reached, I would just reinvoke this method. Normally in other languages, I would probably put this in a separate thread and abort it if I do not get the result in a configurable time. (The timer being external.)

In my case: I have a number of retries and let's say I want to perform an IO action with a timeout. How can I place the IO action in a timeout-ed scope so that it gets recalled after the timeout expires, if and only if the number of retries is greater 0.

Basically: given our IO action like ioMethod::IO String (I have not looked yet in the socket library for Haskell), we'll assume its a black box,

module Retry where

import IOExternal(ioMethod)

retryFunc :: Int -> IO String
retryFunc retries=do
            msg<-retry 5 100 IOExternal 
            return msg

retry :: Int -> Int -> IOExternal -> IO String
retry retries timeout ioMethod = go retries timeout "" where
        go 0       timeout ioMethod  msg =
                    if msg=="" then return "Max Retries reached" 
                               else return msg

        go retries timeout ioMethod  msg counter
               = gogo retries timeout counter msg  where
                     gogo retries timeout 0 msg = return ""
                     gogo retries timeout counter msg
                        = ioMethod>>=gogo retries timeout counter-1 

I do not know how to model this last condition/line.

P.S I am not yet familiar with threading in Haskell (beginner here) and I do think that the timeout-ed scope should perform in different thread,and somehow I need to check it from my main program, and either recall it (if retries>0) or end the main method.

Upvotes: 3

Views: 316

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 153162

You can use timeout to add a timeout to any blocking call, and simple recursion for retries:

retry :: Int -> Int -> IO a -> IO (Maybe a)
retry 0 _ _ = return Nothing
retry numRetries microseconds action = do
    result <- timeout microseconds action
    case result of
        Nothing -> retry (numRetries-1) microseconds action
        Just a  -> return (Just a)

Do read the documentation for caveats about FFI stuff, though.

Upvotes: 3

Related Questions