Ho giocato con il pacchetto UNIX conduit-extra
, che fondamentalmente consente una facile creazione di un server utilizzando socket di dominio UNIX, in particolare utilizzando lo runUnixServer
funciton.Qual è il modo corretto di ripulire le risorse usando ResourceT?
Il problema è che dopo la presenza della funzione non pulisce il file socket, il che significa che deve essere pulito manualmente. Ecco un semplice esempio, che in pratica crea un server echo.
main :: IO()
main = do
let settings = serverSettings "foobar.sock"
runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
ho google un po 'intorno e ha scoperto che il modo corretto di gestire le risorse qui è quello di utilizzare il pacchetto resourcet
. Anche se il problema è che la maggior parte delle API in risorse mi aspettano di allocare la risorsa da sola, che non è il caso di runUnixSever
, che non restituisce nulla.
In un primo momento ho pensato che avrei potuto usare register
, per registrare una funzione che elimina il file, come ad esempio il seguente
main :: IO()
main = runResourceT $ do
register $ removeLink "foobar.sock"
let settings = serverSettings "foobar.sock"
liftIO $ runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
C'è un problema con questo approccio, però, almeno per quanto riguarda la documentazione per allocate
dice:
Questo è quasi identico a chiamare l'allocazione e quindi registrare l'azione di rilascio, ma questo gestisce correttamente il mascheramento delle eccezioni asincrone.
Ciò significa che register
di per sé non gestisce eccezioni asincrone? Se sì, potrebbe essere un problema quando uno dei gestori generato dallo runUnixServer
(i documenti dicono che genera un thread per ogni client) genera un errore?
Una terza e ultima soluzione che ho trovato è l'utilizzo di allocate
, per assicurarsi che le eccezioni asincrone siano gestite correttamente (non sono sicuro che sia davvero necessario in questo caso).
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))
Ma questa è davvero la soluzione migliore? Dal momento che sto creando un valore che non userò mai (return 1)
e quindi utilizzando una funzione const
per ignorare quel valore nel finalizzatore.
Grazie per una risposta super veloce! –