如何使用System.Cron.Schedule处理长时间运行的作业?

时间:2018-01-07 07:30:10

标签: haskell job-scheduling

我正在努力学习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"

1 个答案:

答案 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的实现,了解该方向的指示。