First, I appologize for not having a minimal example (I can attempt to construct one, but for now I have a "before and after" example):
First the "after" which has the memory leak:
protoReceiver :: RIO FdsEnv ()
protoReceiver = do
logItS Info ["Entering FarmPCMessage protoReceiver"]
tMap <- liftIO $ newThreadMap
fdsEnv <- ask
let lgr = fdsLogger fdsEnv
loopBody <- pure $ bracketOnError
(runResourceT $ protoServe fdsEnv tMap readFarmPCMessage)
(\(_,w) -> do
logLogItS Debug lgr ["Entering cleanup for protoReceiver"]
)
(\(server,_) -> do
logLogItS Debug lgr ["Entering FarmPCMessage protoReceiver bracket"]
server
.| mapMC (liftIO . traverse_ (persistFarmEntry fdsEnv))
.| mapMC ((logLogIt Info lgr) . pure)
.| sinkUnits & runConduitRes
)
liftIO loopBody
Here's the "before" code, which does not memory leak:
protoReceiver :: RIO FdsEnv ()
protoReceiver = do
logItS Info ["Entering FarmPCMessage protoReceiver"]
tMap <- liftIO $ newThreadMap
fdsEnv <- ask
let lgr = fdsLogger fdsEnv
(dmgrProtoServe, tcpWorker) <- liftIO $ runResourceT
$ protoServe fdsEnv tMap readFarmPCMessage
liftIO $ runResourceT $ dmgrProtoServe
.| mapMC (liftIO . traverse_ (persistFarmEntry fdsEnv))
.| mapMC ((logLogIt Info lgr) . pure)
.| sinkUnits & runConduit
I did some profiling of the leak, though I'm not sure if it is particularly helpful (any suggestions on better profiling charts appreciated):

