packages feed

natskell-0.0.0.1: internal/Lib/WorkerPool.hs

module Lib.WorkerPool
  ( startWorkerPool
  ) where

import           Control.Concurrent     (forkIO)
import           Control.Concurrent.STM
    ( STM
    , TQueue
    , atomically
    , check
    , isEmptyTQueue
    , orElse
    , readTQueue
    )
import           Control.Exception      (SomeException, try)
import           Control.Monad          (replicateM_, void)

startWorkerPool :: Int -> TQueue (IO ()) -> STM () -> (SomeException -> IO ()) -> IO ()
startWorkerPool concurrency queue stopSignal onError = do
  let workerCount = max 1 concurrency
  replicateM_ workerCount (void (forkIO worker))
  where
    worker = do
      let loop = do
            action <- atomically $
              (Just <$> readTQueue queue)
              `orElse`
              (do
                  stopSignal
                  empty <- isEmptyTQueue queue
                  check empty
                  return Nothing)
            case action of
              Nothing -> return ()
              Just job -> do
                result <- (try job :: IO (Either SomeException ()))
                case result of
                  Left err -> onError err
                  Right () -> pure ()
                loop
      loop