3

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.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152
  • 2
    Please re-insert the code with proper indentation. Note you can just paste the code from your `.hs` file, select it, and press `ctrl`-`k`. – leftaroundabout Aug 23 '18 at 09:31
  • I reformatted it and made some parameter simplifications. – Bercovici Adrian Aug 23 '18 at 10:27
  • Erm, the indentation is still wrong. Imports and top-level definitions must not be indented. – leftaroundabout Aug 23 '18 at 10:31
  • 1
    [retry](http://hackage.haskell.org/package/retry-0.7.6.3/docs/Control-Retry.html#v:retrying) package provides retry logic implementation if you want to avoid writing it by hand. There is also [timeout](http://hackage.haskell.org/package/base-4.11.1.0/docs/System-Timeout.html) combinator in `base` if you just want to limit `IO` action with timeout – Ed'ka Aug 23 '18 at 10:40

1 Answers1

3

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.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380