如何用 System.Cron.Schedule 处理长 运行 的作业?
How to handle long running jobs with System.Cron.Schedule?
我正在努力学习 Haskell。作为第一次尝试,我希望编写一个守护进程,定期 运行 为我做备份工作。
我正在使用 System.Cron.Schedule
to do the scheduling for me and running the restic
可执行文件进行备份。
因为这是一个备份作业,它可能需要一个日志时间到 运行,以防止下一个计划的备份从 运行ning 开始,而前一个备份还没有完成,我想确保我只能拥有作业 运行ning 的 1 个实例。如何防止长时间 运行ning 作业再次 运行?
作为一个简化的示例,如何使以下内容在现有作业完成之前不会每分钟产生另一个作业?
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
的实现。
我正在努力学习 Haskell。作为第一次尝试,我希望编写一个守护进程,定期 运行 为我做备份工作。
我正在使用 System.Cron.Schedule
to do the scheduling for me and running the restic
可执行文件进行备份。
因为这是一个备份作业,它可能需要一个日志时间到 运行,以防止下一个计划的备份从 运行ning 开始,而前一个备份还没有完成,我想确保我只能拥有作业 运行ning 的 1 个实例。如何防止长时间 运行ning 作业再次 运行?
作为一个简化的示例,如何使以下内容在现有作业完成之前不会每分钟产生另一个作业?
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
的实现。