pgmq-inspect-0.7.0.0: src/Pgmq/Inspect/Budget.hs
-- | One runtime-wide nonblocking admission gate for HTTP and feed reads.
module Pgmq.Inspect.Budget (InspectionBudget, withInspectionBudget, withInspectionPermit) where
import Control.Concurrent.STM
import Control.Exception (bracket, finally, mask)
import Pgmq.Inspect.Config
newtype InspectionBudget = InspectionBudget (TVar Int)
withInspectionBudget :: InspectConfig -> (InspectionBudget -> IO a) -> IO a
withInspectionBudget cfg k = bracket (InspectionBudget <$> newTVarIO (maxConcurrentReads cfg)) (const (pure ())) k
-- | Reject promptly when full; release on success, failure and cancellation.
-- No retries or detached work are created here.
withInspectionPermit :: InspectionBudget -> IO a -> IO (Maybe a)
withInspectionPermit (InspectionBudget slots) action = mask $ \restore -> do
acquired <- atomically $ do
n <- readTVar slots
if n <= 0 then pure False else writeTVar slots (n - 1) >> pure True
if acquired then Just <$> (restore action `finally` atomically (modifyTVar' slots (+ 1))) else pure Nothing