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



我正在尝试学习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"

这是@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 的实现。

最新更新