fix(jobs): cleaner shutdown of job-pool-manager

This commit is contained in:
Gregor Kleen 2019-09-26 11:56:33 +02:00
parent 98ff5ac303
commit adc8d466ac
3 changed files with 48 additions and 10 deletions

View File

@ -380,7 +380,7 @@ develMain = runResourceT $ do
void . liftIO $ awaitTermination `race` runSettings wsettings app void . liftIO $ awaitTermination `race` runSettings wsettings app
-- | The @main@ function for an executable running this site. -- | The @main@ function for an executable running this site.
appMain :: forall m. MonadUnliftIO m => m () appMain :: forall m. (MonadUnliftIO m, MonadMask m) => m ()
appMain = runResourceT $ do appMain = runResourceT $ do
settings <- getAppSettings settings <- getAppSettings
@ -472,7 +472,7 @@ appMain = runResourceT $ do
foundationStoreNum :: Word32 foundationStoreNum :: Word32
foundationStoreNum = 2 foundationStoreNum = 2
getApplicationRepl :: (MonadResource m, MonadUnliftIO m) => m (Int, UniWorX, Application) getApplicationRepl :: (MonadResource m, MonadUnliftIO m, MonadMask m) => m (Int, UniWorX, Application)
getApplicationRepl = do getApplicationRepl = do
settings <- getAppDevSettings settings <- getAppDevSettings
foundation <- makeFoundation settings foundation <- makeFoundation settings

View File

@ -86,6 +86,7 @@ instance Exception JobQueueException
handleJobs :: ( MonadResource m handleJobs :: ( MonadResource m
, MonadLogger m , MonadLogger m
, MonadUnliftIO m , MonadUnliftIO m
, MonadMask m
) )
=> UniWorX -> m () => UniWorX -> m ()
-- | Spawn a set of workers that read control commands from `appJobCtl` and address them as they come in -- | Spawn a set of workers that read control commands from `appJobCtl` and address them as they come in
@ -97,7 +98,7 @@ handleJobs foundation@UniWorX{..}
| otherwise = do | otherwise = do
UnliftIO{..} <- askUnliftIO UnliftIO{..} <- askUnliftIO
jobPoolManager <- allocateLinkedAsync . unliftIO $ manageJobPool foundation jobPoolManager <- allocateLinkedAsyncWithUnmask $ \unmask -> unliftIO $ manageJobPool foundation unmask
jobCron <- allocateLinkedAsync . unliftIO $ manageCrontab foundation jobCron <- allocateLinkedAsync . unliftIO $ manageCrontab foundation
@ -129,15 +130,32 @@ manageJobPool :: forall m.
( MonadResource m ( MonadResource m
, MonadLogger m , MonadLogger m
, MonadUnliftIO m , MonadUnliftIO m
, MonadMask m
) )
=> UniWorX -> m () => UniWorX -> (forall a. IO a -> IO a) -> m ()
manageJobPool foundation@UniWorX{..} manageJobPool foundation@UniWorX{..} unmask = shutdownOnException $
= flip runContT return . forever . join . atomically $ asum flip runContT return . forever . join . atomically $ asum
[ spawnMissingWorkers [ spawnMissingWorkers
, reapDeadWorkers , reapDeadWorkers
, terminateGracefully , terminateGracefully
] ]
where where
shutdownOnException :: m a -> m a
shutdownOnException act = do
UnliftIO{..} <- askUnliftIO
actAsync <- allocateLinkedAsyncMasked $ unliftIO act
let handleExc e = do
atomically $ do
jState <- tryReadTMVar appJobState
for_ jState $ \JobState{jobShutdown} -> tryPutTMVar jobShutdown ()
void $ wait actAsync
throwM e
unmask (wait actAsync) `catchAll` handleExc
num :: Int num :: Int
num = fromIntegral $ foundation ^. _appJobWorkers num = fromIntegral $ foundation ^. _appJobWorkers

View File

@ -1,5 +1,7 @@
module UnliftIO.Async.Utils module UnliftIO.Async.Utils
( allocateAsync, allocateLinkedAsync ( allocateAsync, allocateLinkedAsync
, allocateAsyncWithUnmask, allocateLinkedAsyncWithUnmask
, allocateAsyncMasked, allocateLinkedAsyncMasked
) where ) where
import ClassyPrelude hiding (cancel, async, link) import ClassyPrelude hiding (cancel, async, link)
@ -17,3 +19,21 @@ allocateAsync = fmap (view _2) . flip allocate cancel . liftIO . async
allocateLinkedAsync :: forall m a. (MonadUnliftIO m, MonadResource m) => IO a -> m (Async a) allocateLinkedAsync :: forall m a. (MonadUnliftIO m, MonadResource m) => IO a -> m (Async a)
allocateLinkedAsync = uncurry (<$) . (id &&& link) <=< allocateAsync allocateLinkedAsync = uncurry (<$) . (id &&& link) <=< allocateAsync
allocateAsyncWithUnmask :: forall m a.
MonadResource m
=> ((forall b. IO b -> IO b) -> IO a) -> m (Async a)
allocateAsyncWithUnmask act = fmap (view _2) . flip allocate cancel . liftIO $ asyncWithUnmask act
allocateLinkedAsyncWithUnmask :: forall m a. (MonadUnliftIO m, MonadResource m) => ((forall b. IO b -> IO b) -> IO a) -> m (Async a)
allocateLinkedAsyncWithUnmask act = uncurry (<$) . (id &&& link) =<< allocateAsyncWithUnmask act
allocateAsyncMasked :: forall m a.
MonadResource m
=> IO a -> m (Async a)
allocateAsyncMasked act = fmap (view _2) . flip allocate cancel . liftIO $ asyncWithUnmask (const act)
allocateLinkedAsyncMasked :: forall m a. (MonadUnliftIO m, MonadResource m) => IO a -> m (Async a)
allocateLinkedAsyncMasked = uncurry (<$) . (id &&& link) <=< allocateAsyncMasked