`retry` family of functions in Control.Exception
Motivation
There is a strange behavior on Windows where deleting the parent directory of a recently-removed child directory fails. This happens because a file/directory may still be used by a program (e.g. antivirus) for a very short amount of time (<100us).
This problem arose while working on the hakyll
package, where on Windows only, some tests would fail because directories were not completely removed. The solution, proposed here, was to retry to remove directories, with a small delay between tries.
Related problems have been discussed on the issue tracker for the win32
library and on the issue tracker for the directory
library. The consensus seems to be that retrying is general enough to warrant implementing this in base
, rather than directory
or win32
.
Proposal
I am proposing to add a family of retry
functions to the Control.Exception
module which might look like this:
import Control.Exception.Base (Exception)
-- Retry computation at most \n\ times for selected exceptions.
retry :: Exception e
=> (e -> Bool) -- ^ Exception predicate
-> Int -- ^ Maximum number of retries
-> IO a -> IO a
-- Retry computation at most \n\ times for selected exceptions.
-- An action (such as a cleanup or delay) will be performed before every retry.
retryWith :: Exception e
=> (e -> Bool) -- ^ Exception predicate
-> IO () -- ^ Cleanup action
-> Int -- ^ Maximum number of retries
-> IO a -> IO a
Some implementations can be found on Hackage, e.g. in the extra
library. However, given the motivation for retrying to delete directories on Windows, I believe that the community should coalesce on a "central" retrying mechanism.
Given interest for this feature, I volunteer to put together a pull request.