我正在努力学习Haskell。作为第一次尝试,我正在寻找一个定期为我运行备份工作的守护进程。
我正在使用System.Cron.Schedule
为我执行调度并运行restic
可执行文件来进行备份。
由于这是一个备份作业,它可能需要一个日志时间来运行,以防止下一个计划备份在前一个尚未完成时运行,我想确保我只能拥有1个正在运行的作业实例。如何防止长时间运行的作业再次运行?
作为一个简单的例子,在现有工作完成之前,如何让以下内容不会每分钟产生另一个工作?
main :: IO ()
main = do
tids <- execSchedule $ do
addJob doBackup "* * * * *"
print tids
doBackup :: IO ()
doBackup = do
putStrLn "Backing up system..."
threadDelay 70000000
putStrLn "Backup finished"
答案 0 :(得分:1)
这是@Alec建议的实施。这会创建一个MVar ()
(基本上是一个信号量),然后每次运行时,它会检查MVar
在继续之前是否空闲,否则就会死亡。
import Control.Concurrent.MVar
import Control.Monad
main :: IO ()
main = do sem <- newMVar () -- starts off not taken
tids <- execSchedule $ addJob (doBackup sem) "* * * * *" -- do x = x
print tids
forever $ threadDelay maxBound
-- all threads exit when main exits. ^ stops that from happening
-- Control.Monad.forever x = let loop = x >> loop in loop
-- don't do forever $ return () unless you want a CPU-nomming busyloop
doBackup :: MVar () -> IO ()
doBackup sem = do res <- tryTakeMVar sem
-- gives Nothing if the sem is taken and Just () if it isn't
-- you DON'T want takeMVar, since that'll block until sem is
-- free, essentially queueing the jobs up instead of
-- canceling the ones that run too early.
case res of
Nothing -> return () -- already taken? do nothing
Just () -> do putStrLn "Backing up system..."
threadDelay 70000000
putStrLn "Backup finished"
putMVar sem () -- release the lock
仅供参考:这不是例外安全的。请参阅withMVar
的实现,了解该方向的指示。