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))