Есть такой вопрос: идёт поток запросов к TCP-серверу. Я этот поток обрабатываю, вытаскиваю данные, делаю разные запросы к другим серверам, результат возвращаю.
По сути, мой код является прокси-сервером, который дружит старое ПО с новым. Написан на кондуитах.
С ним есть проблема, решить которую я не смог: теряются ресурсы в виде файловых дескрипторов. Происходит это из-за подобного подхода:
main :: IO ()
main =
runTCPServer (serverSettings 4002 hostnameListen) $ \proxy ->
appSource proxy $= … $$ appSink proxy
…
condCyrusGet :: (MonadIO m, Monad m) => Conduit ByteString m ByteString
condCyrusGet = awaitForever $ \bs -> do
res <- liftIO $ cyrusSock bs
yield res
cyrusAppAddr = "/run/cyrusserv/cyrus.socket"
cyrusSock :: ByteString -> IO ByteString
cyrusSock ar = do
soc <- NS.socket AF_UNIX Stream 0
NS.connect soc (SockAddrUnix cyrusAppAddr)
NSB.send soc ar
msg <- NSB.recv soc 32768
NS.sClose soc
return msg
при подключении к сокету, который слушается совсем простым сервером:
hostnameListen = "/run/cyrusserv/cyrus.socket"
cyrusHostname = "127.0.0.1"
main :: IO ()
main =
runUnixServer (CNU.serverSettings hostnameListen) $ \proxy ->
runTCPClient (CN.clientSettings 12345 cyrusHostname) $ \client_cyrus ->
runConcurrently $
Concurrently (appSource proxy $$ appSink client_cyrus) *>
Concurrently (appSource client_cyrus $$ appSink proxy)
Его предназначением является связь каких-то локально запущенных серверов с одним удалённым.
Не закрываются вовремя подключения к Unix-сокету в функции cyrusSock и постепенно количество незакрытых соединений растёт. В итоге, всё заканчивается
socket: resource exhausted (Too many open files)
Полагаю, что проблема решается загоном этой функции cyrusSock и вообще, общения с этим Unix-сокетом через кондуит, примерно так, как сделано в последнем куске кода, но как это сделать — не представляю. Использовать bracket?
Что подскажет уважаемое сообщество?