packages feed

cachix-1.9.1: src/Cachix/Daemon/TaskQueue.hs

module Cachix.Daemon.TaskQueue
  ( TaskQueue,
    newTaskQueue,
    writeTask,
    tryWriteTask,
    readTask,
    closeTaskQueue,
  )
where

import Cachix.Daemon.Types.TaskQueue (Prioritized (..), TaskQueue (..))
import Control.Concurrent.STM.TVar
import Data.PQueue.Max qualified as MaxQueue
import Protolude

-- | Create a new empty task queue
newTaskQueue :: STM (TaskQueue a)
newTaskQueue = TaskQueue <$> newTVar (MaxQueue.empty, 0, False)

-- | Write an item to the queue (always succeeds unless queue is closed)
writeTask :: (Ord a) => TaskQueue a -> a -> STM ()
writeTask (TaskQueue tvar) task = do
  (queue, seqNum, closed) <- readTVar tvar
  unless closed $ do
    let prioritized = Prioritized task seqNum
        nextSeq = seqNum + 1 -- Word32 wraps around naturally on overflow
    writeTVar tvar (MaxQueue.insert prioritized queue, nextSeq, closed)

-- | Try to write an item to the queue
-- Returns Just True if successful, Just False if closed, Nothing if would block (never happens)
tryWriteTask :: (Ord a) => TaskQueue a -> a -> STM (Maybe Bool)
tryWriteTask (TaskQueue tvar) task = do
  (queue, seqNum, closed) <- readTVar tvar
  if closed
    then return (Just False)
    else do
      let prioritized = Prioritized task seqNum
          nextSeq = seqNum + 1
      writeTVar tvar (MaxQueue.insert prioritized queue, nextSeq, closed)
      return (Just True)

-- | Read an item from the queue
-- Returns Nothing if queue is closed, retries if queue is empty but open
readTask :: (Ord a) => TaskQueue a -> STM (Maybe a)
readTask (TaskQueue tvar) = do
  (queue, seqNum, closed) <- readTVar tvar
  case MaxQueue.maxView queue of
    Nothing ->
      if closed
        then return Nothing
        else retry
    Just (prioritized, queue') -> do
      writeTVar tvar (queue', seqNum, closed)
      return (Just (pTask prioritized))

-- | Close the queue
closeTaskQueue :: TaskQueue a -> STM ()
closeTaskQueue (TaskQueue tvar) = modifyTVar' tvar $ \(queue, seqNum, _) -> (queue, seqNum, True)