每天1小时后如何开始cronjob?


16

我需要每天开始一次cronjob,但每天要过一个小时。到目前为止,除一年中的1天外,我大部分时间都可以使用:

0 0 * * * sleep $((3600 * (10#$(date +\%j) \% 24))) && /usr/local/bin/myprog

当一年的日期是365时,工作将从5:00开始,但是第二天(不计​​算counting年)的一年中的一天将为1,因此,工作将从1:00开始。我该如何摆脱这种困境?


1
是否有理由不每隔25小时才启动一次?
HalosGhost 2014年

7
你到底会怎么做?* / 25在小时位置将无法解决。
桦木

@HalosGhost感谢您的建议!我写了一个基于at的简单实现。
Giulio Muscarello 2014年

Answers:


23

我的首选解决方案是每小时开始一次工作,但让脚本本身检查是否该运行或退出,然后在25次中不进行任何24次退出。

crontab:

0 * * * *    /usr/local/bin/myprog

在顶部myprog

[ 0 -eq $(( $(date +%s) / 3600 % 25 )) ] || exit 0

如果您不想对脚本本身进行任何更改,还可以在crontab条目中放入“运行时间”检查,但这会导致很长的难看行:

0 * * * *    [ 0 -eq $(( $(date +\%s) / 3600 \% 25 )) ] && /usr/local/bin/myprog

1
需要在crontab中使用反斜杠转义'%'。
桦木

@桦木,我从来不知道!我想我从未尝试过在crontab中包含%。感谢您的更正,我已经编辑了答案。
Celada 2014年

1
这对我来说很好。我不知道OP在夏时制方面想做些什么(春天来了,落后了),但是OP应该做出相应的调整。
emory

我会对分部的四舍五入有些担心。如果由于某种原因date从内核返回的时间早于1ms您希望脚本运行的时间,则检查将给出错误的结果。
kasperd 2014年

1
@kasperd我不知道,我想您可能对不同的CPU报告不同的时间是正确的。至于ntpd,它确实尽力只摆时钟而不跳时钟,特别是为了避免这种问题,但您是对的,它ntpdate有时会使时间倒退。至于cron错误计算其睡眠延迟,我敢肯定那会被认为是一个错误!不过,点取和解决方法是安排作业30分钟才这是不太可能的小时,使问题...或者在算术表达式服用reamainder前加±1800 3600国防部
切拉达

7

如果您的系统具有systemd,则可以为此使用timers事件。只需定义一个新服务,其中应包含要执行的命令/任务,然后使用以下OnUnitActiveSec选项创建一个计时器事件:

[Unit]
Description=daily + 1 hour task

[Timer]
OnUnitActiveSec=25h # run 25 hours after service was last started
AccuracySec=10min

[Install]
WantedBy=timers.target

为这些文件使用相同的名称,只是不用.service你使用.timer

合成:

  1. job.service/etc/systemd/system/目录中创建一个名为的文件。
  2. 填写必要的信息。您可以使用验证配置systemctl status job.service
  3. 创建一个名为文件job.timer/etc/systemd/system/
  4. 填写所需信息:

    [Unit]
    Description=daily + 1 hour task
    
    [Timer]
    OnUnitActiveSec=25h # run 25 hours after service was last started
    AccuracySec=10min
    
    [Install]
    WantedBy=timers.target
    
  5. 使用以下方法验证计时器 systemctl list-timers
  6. 做完了

如果我不喜欢cron的简单性,那么我会使用launchd,这比您的systemd示例需要更少的工作。
桦木

6

如果您不介意使用cronjobs以外的其他工具,我建议您使用鲜为人知的Utility at。只需编写一个包装器脚本,两个脚本都计划自己在25小时内运行,然后调用程序。这似乎是最干净的解决方案。
例如,您可以在〜/ script.sh中编写以下代码:

echo "bash ~/script.sh" | at now + 25 hours
/usr/bin/yourprogram

然后只需运行bash ~/script.sh一次。

感谢@HalosGhost提供了在25小时内安排一次作业的想法。


2
at为此目的使用存在两个问题:(1)如果作业即使一次执行都无法正确执行,也可能无法重新安排自身的时间,不仅是下一次执行,而且所有将来的执行都将被有效取消,直到有人注意到为止;以及(2)由于作业需要花费一些非零的时间来运行,因此使用天真now + 25 hours意味着每次都会在几秒钟(或更长时间)后运行,并且这种滞后会随着时间的流逝而累积,最终最终以完全错误的方式运行时间。
Celada 2014年

2
您对#1是正确的;我不太确定第二名。尽管我没有任何数据,但我认为时钟更改与at作业被触发并随后重新安排之间的延迟并不大到足以引起注意-特别是考虑到的分辨率at限制为分钟并启动所有作业在[时间]:00。
Giulio Muscarello 2014年

1
@Celada:在at脚本中安排下一个at作业的第一件事可以避免这些问题。尽管如此,如果发生错误,则整个链都将断开,这可能是不希望的:如果用例是“仅在可行时运行”,那么不重新启动是一个很棒的功能。但是,如果用例是“总是运行,即使最后一次失败”,那at也不是正确的工具。
主教
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.