`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.