fradrive/src/Handler/Utils/Concurrent.hs

45 lines
1.4 KiB
Haskell

-- SPDX-FileCopyrightText: 2024 Steffen Jost <s.jost@fraport.de>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
module Handler.Utils.Concurrent
( module Handler.Utils.Concurrent
) where
-- NOTE: use `retrySTM` and `checkSTM` instead of `retry` or `check`
import Import
import UnliftIO.Concurrent as Handler.Utils.Concurrent hiding (yield)
maybeTimeoutHandler :: Maybe Int -> HandlerFor site a -> HandlerFor site (Maybe a)
maybeTimeoutHandler Nothing = fmap Just
maybeTimeoutHandler (Just secs) = timeoutHandler $ bool maxBound micro (micro > 0)
where
micro = 1000000 * secs
-- | Run a handler action until it finishes or if it exceeds a given number of microseconds via `registerDelay`
timeoutHandler :: Int -> HandlerFor site a -> HandlerFor site (Maybe a)
timeoutHandler maxWait act = do
innerAct <- handlerToIO
(hresult, tid) <- liftIO $ do
hresult <- newTVarIO Nothing
tid <- forkIO $ do
res <- innerAct act
atomically $ writeTVar hresult $ Just res
return (hresult, tid)
res <- liftIO $ do
flag <- registerDelay maxWait
atomically $ do
out <- readTVar flag
res <- readTVar hresult
checkSTM $ out || isJust res
return res
case res of
Nothing -> liftIO $ do
killThread tid
readTVarIO hresult -- read once more after kill to ensure that any result is noticed
_ -> return res