I think we should keep the use of link
but dispense with the nested withAsync
s.
Instead of that, we should keep an explicit set of Async
values in a mutable reference. The main thread can cancel the pending asyncs as needed.
Something like (haven’t actually tested it )
main :: IO ()
main = do
ref <- newIORef $ Data.Set.empty @(Async ())
let register theAsync =
modifyIORef' ref $ Data.Set.insert theAsync
finallyDeregister theAsync = flip finally $
modifyIORef' ref $ Data.Set.delete theAsync
launch conn = fixIO $ \theAsync -> async $ finallyDeregister theAsync $ handle conn
loop = do
bracketOnError awaitConn releaseConn $ \conn -> do
bracketOnError (launch conn) uninterruptibleCancel $ \theAsync -> do
link theAsync
register theAsync
loop
cleanup = do
asyncs <- readIORef ref
for_ asyncs uninterruptibleCancel
loop `onException` cleanup