mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-18 13:02:11 +03:00
2dfbf99b41
* Remove unused ExitCode constructors * Simplify shutdown logic * Update server/src-lib/Hasura/App.hs Co-authored-by: Brandon Simmons <brandon@hasura.io> * WIP: fix zombie thread issue * Use forkCodensity for the schema sync thread * Use forkCodensity for the oauthTokenUpdateWorker * Use forkCodensity for the schema update processor thread * Add deprecation notice * Logger threads use Codensity * Add the MonadFix instance for Codensity to get log-sender thread logs * Move outIdleGC out to the top level, WIP * Update forkImmortal fuction for more logging info * add back the idle GC to Pro * setupAuth * use ImmortalThreadLog * Fix tests * Add another finally block * loud warnings * Change log level * hlint * Finalize the logger in the correct place * Add ManagedT * Update server/src-lib/Hasura/Server/Auth.hs Co-authored-by: Brandon Simmons <brandon@hasura.io> * Comments etc. Co-authored-by: Brandon Simmons <brandon@hasura.io> Co-authored-by: Naveen Naidu <naveennaidu479@gmail.com> GitOrigin-RevId: 156065c5c3ace0e13d1997daef6921cc2e9f641c
74 lines
3.1 KiB
Haskell
74 lines
3.1 KiB
Haskell
{-# LANGUAGE DerivingVia #-}
|
|
|
|
module Control.Monad.Trans.Managed where
|
|
|
|
import Prelude
|
|
|
|
import Control.Exception.Lifted (bracket, bracket_)
|
|
import Control.Monad.Codensity (Codensity(..))
|
|
import Control.Monad.Fix (MonadFix(..))
|
|
import Control.Monad.IO.Class (MonadIO, liftIO)
|
|
import Control.Monad.Reader.Class (MonadReader)
|
|
import Control.Monad.State.Class (MonadState)
|
|
import Control.Monad.Trans (MonadTrans(..))
|
|
import Control.Monad.Trans.Control (MonadBaseControl)
|
|
import Control.Monad.Trans.Reader (ReaderT(..))
|
|
import GHC.IO.Unsafe (unsafeDupableInterleaveIO)
|
|
|
|
import qualified Control.Concurrent as C
|
|
|
|
-- | This type is like a transformer version of the @Managed@ monad from the
|
|
-- @managed@ library. It can be used to manage resources by pairing together
|
|
-- their allocation with their finalizers.
|
|
--
|
|
-- The documentation for the @managed@ library is an excellent introduction to
|
|
-- the idea here.
|
|
--
|
|
-- We could use 'Codensity' directly, but we'd have to define an orphan instance
|
|
-- for 'MonadFix'. This also gives us the opportunity to give it a slightly more
|
|
-- friendly name.
|
|
--
|
|
-- We could also have used @ResourceT@, but that would have involved writing
|
|
-- instances for @MonadUnliftIO@. That could still be a good option to consider
|
|
-- later, however.
|
|
newtype ManagedT m a = ManagedT { runManagedT :: forall r. (a -> m r) -> m r }
|
|
deriving ( Functor
|
|
, Applicative
|
|
, Monad
|
|
, MonadIO
|
|
, MonadReader r
|
|
, MonadState s
|
|
) via (Codensity m)
|
|
deriving MonadTrans via Codensity
|
|
|
|
-- | Allocate a resource by providing setup and finalizer actions.
|
|
allocate :: MonadBaseControl IO m => m a -> (a -> m b) -> ManagedT m a
|
|
allocate setup finalize = ManagedT (bracket setup finalize)
|
|
|
|
-- | Allocate a resource but do not return a reference to it.
|
|
allocate_ :: MonadBaseControl IO m => m a -> m b -> ManagedT m ()
|
|
allocate_ setup finalize = ManagedT (\k -> bracket_ setup finalize (k ()))
|
|
|
|
-- | Run the provided computation by returning its result, and run any finalizers.
|
|
-- Watch out: this function might leak finalized resources.
|
|
lowerManagedT :: Monad m => ManagedT m a -> m a
|
|
lowerManagedT m = runManagedT m return
|
|
|
|
hoistManagedTReaderT :: Monad m => r -> ManagedT (ReaderT r m) a -> ManagedT m a
|
|
hoistManagedTReaderT r cod = ManagedT $ \k ->
|
|
runReaderT (runManagedT cod (lift . k)) r
|
|
|
|
-- | We need this instance to tie the knot when initializing resources.
|
|
-- It'd be nice if we could do this with a 'MonadFix' constraint on the underlying
|
|
-- monad, but here we just use 'MonadIO' to tie the knot using a lazily-evaluated
|
|
-- 'MVar'-based promise for the eventual result.
|
|
--
|
|
-- We need to be careful not to leak allocated resources via the use of
|
|
-- recursively-defined monadic actions when making use of this instance.
|
|
instance MonadIO m => MonadFix (ManagedT m) where
|
|
mfix f = ManagedT \k -> do
|
|
m <- liftIO C.newEmptyMVar
|
|
ans <- liftIO $ unsafeDupableInterleaveIO (C.readMVar m)
|
|
runManagedT (f ans) \a -> do
|
|
liftIO $ C.putMVar m a
|
|
k a |