happstack-util-0.3.1: src/Happstack/Util/Daemonize.hs
module Happstack.Util.Daemonize where
import System.Directory
import System.Environment
import System.Exit
import System.Time
import Control.Concurrent
import Control.Exception.Extensible as E
import Control.Monad.Error
import Happstack.Crypto.SHA1
import Happstack.Util.Common
{--
1. don't start the app if already running. the app is already running if something
has written to the daemon file recently
2. kill the app if the binary has changed since the app started
--}
-- Will placing the lock-file in the current directory work if we run the application from cron?
daemonize :: FilePath -> IO a -> IO a
daemonize binarylocation main =
do
startTime <- getClockTime
tid1 <- exitIfAlreadyRunning startTime
mId <- myThreadId
tid2 <- appCheck binarylocation startTime mId
main `finally` mapM killThread [tid1,tid2]
where
seconds n = noTimeDiff { tdSec = n }
exitIfAlreadyRunning startTime =
do
uniqueId <- getDaemonizedId
let name = ".haskell_daemon." ++ uniqueId
fe <- doesFileExist name
when fe $
do
daemonTime <- getModificationTime name
when (diffClockTimes startTime daemonTime < seconds 2) $
exitWith ExitSuccess >> return ()
periodic (repeat 1) $ writeFile name "daemon"
appCheck bl startTime mId = periodic (repeat 1) $
do
fe <- doesFileExist bl
if not fe then return () else do
appModTime <- getModificationTime bl
when (startTime < appModTime) (E.throwTo mId ExitSuccess) -- throws to the main thread
getDaemonizedId :: IO String
getDaemonizedId
= do prog <- getProgName
args <- getArgs
return (sha1 (prog ++ unwords args))