I've been playing around with conduit-extra
's UNIX package, which basically allows for an easy creation of a server using UNIX domain sockets, specifically using the runUnixServer
funciton.
The problem is that after the function exists it doesn't cleanup the socket file, which means it needs to be cleaned up manually. Here's a simple example, which basically creates an echo server.
main :: IO ()
main = do
let settings = serverSettings "foobar.sock"
runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
I've google around a bit and found that the correct way to handle the resources here is by using the resourcet
package. Though the problem is that most of the APIs in resources expect me to allocate the resource myself, which isn't the case of runUnixSever
, which doesn't return anyhting.
At first I thought I could use register
, to register a function that removes the file, such as the following
main :: IO ()
main = runResourceT $ do
register $ removeLink "foobar.sock"
let settings = serverSettings "foobar.sock"
liftIO $ runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
There's a problem with this approach though, at least as far as the documentation for allocate
says:
This is almost identical to calling the allocation and then registering the release action, but this properly handles masking of asynchronous exceptions.
Does this mean that register
in itself doesn't handle asynchronous exceptions? If so, could that be a problem when one of the handlers spawned by the runUnixServer
(docs say it spawns a thread for each client) raises an error?
A third and final solution that I came up with is by using allocate
, in order to make sure that the asynchronous exceptions are handled properly (I'm not sure if it is really necessary in this case).
main :: IO ()
main = runResourceT $ do
allocate (return 1) (const $ removeLink "foobar.sock")
let settings = serverSettings "foobar.sock"
liftIO $ runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
But is this really the best solution? Since I'm creating a value which I'll never use (return 1)
and then using a const
function to ignore that value in the finalizer.