graphql-engine/server/src-test/Control/Monad/TimeLimit.hs
Tom Harding e0c0043e76 Upgrade Ormolu to 0.7.0.0
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9284
GitOrigin-RevId: 2f2cf2ad01900a54e4bdb970205ac0ef313c7e00
2023-05-24 13:53:53 +00:00

41 lines
1.2 KiB
Haskell

module Control.Monad.TimeLimit
( runWithTimeLimit,
succeedsWithinTimeLimit,
)
where
import Control.Concurrent (newEmptyMVar, putMVar, tryTakeMVar)
import Control.Concurrent.Async (async)
import Control.Concurrent.Async qualified as Async
import Control.Concurrent.Extended (sleep)
import Hasura.Prelude
-- | Runs an action with a time limit of approximately 0.1s.
-- If the time taken to perform the action exceeds this limit,
-- it returns 'Nothing'.
runWithTimeLimit :: (MonadIO m) => IO a -> m (Maybe a)
runWithTimeLimit action = liftIO do
var <- newEmptyMVar
thread <- async do
value <- action
putMVar var $! value
result <-
foldr1 continueOnFail $ replicate 10 do
sleep 0.01
tryTakeMVar var
Async.cancel thread
pure result
where
continueOnFail step nextStep =
step >>= \case
Nothing -> nextStep
Just res -> pure (Just res)
-- | Runs an action with a time limit of approximately 0.1s.
-- If the time taken to perform the action exceeds this limit,
-- it fails.
succeedsWithinTimeLimit :: (MonadIO m, MonadFail m) => IO a -> m a
succeedsWithinTimeLimit action =
runWithTimeLimit action
`onNothingM` fail "failed to compute in reasonable time"