keter/Keter/Process.hs

81 lines
3.1 KiB
Haskell
Raw Normal View History

2012-05-14 11:15:50 +04:00
{-# LANGUAGE NoImplicitPrelude #-}
2012-05-17 10:32:11 +04:00
{-# LANGUAGE TemplateHaskell #-}
2012-05-06 14:28:18 +04:00
module Keter.Process
( run
, terminate
, Process
) where
2012-05-14 11:15:50 +04:00
import Keter.Prelude
2012-10-04 21:16:45 +04:00
import Keter.Logger (Logger, attach, LogPipes (..), mkLogPipe)
2012-05-17 11:59:17 +04:00
import Data.Time (diffUTCTime)
2012-10-16 23:21:11 +04:00
import Data.Conduit.Process.Unix (forkExecuteFile, waitForProcess, killProcess, terminateProcess)
import System.Process (ProcessHandle)
2012-10-04 21:16:45 +04:00
import Prelude (error)
import Filesystem.Path.CurrentOS (encode)
import Data.Text.Encoding (encodeUtf8)
import Data.Conduit (($$))
2012-10-16 17:13:26 +04:00
import Control.Exception (onException)
2012-05-06 14:28:18 +04:00
2012-10-16 23:21:11 +04:00
data Status = NeedsRestart | NoRestart | Running ProcessHandle
2012-05-06 14:28:18 +04:00
-- | Run the given command, restarting if the process dies.
run :: FilePath -- ^ executable
-> FilePath -- ^ working directory
-> [String] -- ^ command line parameter
-> [(String, String)] -- ^ environment
2012-05-17 10:32:11 +04:00
-> Logger
2012-05-14 12:03:57 +04:00
-> KIO Process
2012-05-17 10:32:11 +04:00
run exec dir args env logger = do
2012-05-14 12:03:57 +04:00
mstatus <- newMVar NeedsRestart
2012-05-17 11:59:17 +04:00
let loop mlast = do
2012-05-14 12:03:57 +04:00
next <- modifyMVar mstatus $ \status ->
2012-05-06 14:28:18 +04:00
case status of
NoRestart -> return (NoRestart, return ())
_ -> do
2012-05-17 11:59:17 +04:00
now <- getCurrentTime
case mlast of
Just last | diffUTCTime now last < 5 -> do
log $ ProcessWaiting exec
threadDelay $ 5 * 1000 * 1000
_ -> return ()
2012-10-04 21:16:45 +04:00
(pout, sout) <- mkLogPipe
(perr, serr) <- mkLogPipe
res <- liftIO $ forkExecuteFile
(encode exec)
(map encodeUtf8 args)
(Just $ map (encodeUtf8 *** encodeUtf8) env)
(Just $ encode dir)
(Just $ return ())
(Just sout)
(Just serr)
2012-05-14 12:03:57 +04:00
case res of
Left e -> do
2012-10-12 14:02:58 +04:00
$logEx e
2012-10-04 21:16:45 +04:00
void $ liftIO $ return () $$ sout
void $ liftIO $ return () $$ serr
2012-05-14 12:03:57 +04:00
return (NeedsRestart, return ())
2012-10-04 21:16:45 +04:00
Right pid -> do
attach logger $ LogPipes pout perr
2012-05-14 12:03:57 +04:00
log $ ProcessCreated exec
2012-10-16 17:13:26 +04:00
return (Running pid, do
2012-10-21 08:48:34 +04:00
_ <- liftIO $ waitForProcess pid `onException` killProcess pid
2012-10-16 17:13:26 +04:00
loop (Just now))
2012-05-06 14:28:18 +04:00
next
2012-05-17 11:59:17 +04:00
forkKIO $ loop Nothing
2012-05-06 14:28:18 +04:00
return $ Process mstatus
-- | Abstract type containing information on a process which will be restarted.
2012-05-14 12:03:57 +04:00
newtype Process = Process (MVar Status)
2012-05-06 14:28:18 +04:00
-- | Terminate the process and prevent it from being restarted.
2012-05-14 12:03:57 +04:00
terminate :: Process -> KIO ()
2012-05-06 14:28:18 +04:00
terminate (Process mstatus) = do
2012-05-14 12:03:57 +04:00
status <- swapMVar mstatus NoRestart
2012-05-06 14:28:18 +04:00
case status of
2012-10-16 23:21:11 +04:00
Running pid -> do
void $ liftIO $ terminateProcess pid
threadDelay 1000000
void $ liftIO $ killProcess pid
2012-05-06 14:28:18 +04:00
_ -> return ()