问题描述
好的,我有一个cron,我需要每30秒运行一次。
这是我有的:
*/30 * * * * /bin/bash -l -c 'cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'''
它运行,但这是每30分钟还是30秒运行一次?
此外,我一直在阅读如果我经常运行它,cron可能不是最好的工具。还有其他更好的工具,我可以在Ubuntu 11.04上使用或安装,这将是一个更好的选择吗?有没有办法修复上面的cron?
最佳解决思路
您在分钟说明符中有*/30
– 这意味着每分钟但步长为30(换句话说,每半小时)。由于cron
没有达到sub-minute分辨率,您需要找到另一种方法。
一种可能性,虽然它有点像kludge,但是有两个工作,一个偏移30秒:
* * * * * /path/to/executable param1 param2
* * * * * ( sleep 30 ; /path/to/executable param1 param2 )
两个cron作业实际上每分钟运行一次,但后者将在执行作业的”meat” /path/to/executable
之前等待半分钟。
次佳解决思路
你不能。 Cron的粒度为60秒。
* * * * * cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''
* * * * * sleep 30 && cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''
第三种解决思路
Cron的粒度是几分钟,并不是为了唤醒每个x
秒来运行某些东西。在循环中运行重复任务,它应该做你需要的:
#!/bin/env bash
while [ true ]; do
sleep 30
# do what you need to here
done
第四种思路
不需要两个cron条目,你可以把它放在一个:
* * * * * /bin/bash -l -c "/path/to/executable; sleep 30 ; /path/to/executable"
所以在你的情况下:
* * * * * /bin/bash -l -c "cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'' ; sleep 30 ; cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''"
第五种思路
你可以看看我对this similar question的回答
基本上,我已经在其中包含了一个名为”runEvery.sh”的bash脚本,您可以每隔1分钟使用cron运行该脚本,并将您希望运行的实际命令和您想要运行它的频率作为参数传递。
这样的事情
* * * * * ~/bin/runEvery.sh 5 myScript.sh
第六种思路
Cron作业不能用于在几秒钟内安排作业。即你不能安排一个cron作业每5秒运行一次。另一种方法是编写一个使用sleep 5
命令的shell脚本。
使用bash while循环创建一个shell脚本every-5-seconds.sh,如下所示。
$ cat every-5-seconds.sh
#!/bin/bash
while true
do
/home/ramesh/backup.sh
sleep 5
done
现在,使用nohup
在后台执行此shell脚本,如下所示。即使您从会话中注销,这也将继续执行脚本。这将每5秒执行一次backup.sh shell脚本。
$ nohup ./every-5-seconds.sh &
第七种思路
使用 watch :
$ watch --interval .30 script_to_run_every_30_sec.sh
第八种思路
在目录/etc/cron.d/
中
新建一个文件excute_per_30s
* * * * * yourusername /bin/date >> /home/yourusername/temp/date.txt
* * * * * yourusername sleep 30; /bin/date >> /home/yourusername/temp/date.txt
将每30秒运行一次cron
第九种思路
使用fcron(http://fcron.free.fr/) – 以秒为单位提供粒度,比cron(vixie-cron)更好,功能更丰富,也更稳定。我曾经制作过愚蠢的事情,例如在一台机器上运行非常愚蠢的设置运行大约60个PHP脚本,它仍然可以完成它的工作!
第十种思路
如果您使用SystemD运行最近的Linux操作系统,您可以使用SystemD Timer单元以您希望的任何粒度级别(理论上低至纳秒)运行您的脚本,并且 – 如果您愿意 – 比Cron允许的更灵活的启动规则。无需sleep
kludges
设置比cron文件中的单行要多一些,但如果你需要比”Every minute”更好的东西,那么值得努力。
SystemD计时器模型基本上是这样的 – 计时器是在计时器过去时启动服务单元的单位。
因此,对于要安排的每个脚本/命令,您必须具有服务单元,然后是其他计时器单元。单个计时器单元可以包含多个计划,因此您通常不需要多个计时器和一个服务。
这是一个每10秒记录”Hello World”的简单示例:
/etc/systemd/system/helloworld.service
:
[Unit]
Description=Say Hello
[Service]
ExecStart=/usr/bin/logger -i Hello World
/etc/systemd/system/helloworld.timer
:
[Unit]
Description=Say Hello every 10 seconds
[Timer]
OnBootSec=10
OnUnitActiveSec=10
AccuracySec=1ms
[Install]
WantedBy=timers.target
设置这些单元后(在/etc /systemd /system中,如上所述,对于system-wide设置,或在〜/.config /systemd /user用于user-specific设置),您需要启用计时器(不是服务虽然)通过运行systemctl enable helloworld.timer。如果要立即启动计时器(而不是在重新启动后等待它启动),还要运行systemctl start helloworld.timer。
此处使用的[Timer]
部分字段如下:
-
OnBootSec
– 每次启动后几秒钟启动服务。 -
OnUnitActiveSec
– 在上次启动服务后的几秒钟内启动服务。这就是导致计时器重复并且表现得像cron作业的原因。 -
AccuracySec
– 设置计时器的准确性。定时器仅与此字段集一样准确,默认值为1分钟(模拟cron)。不要求最佳精度的主要原因是提高功耗 – 如果SystemD可以安排下一次运行与其他事件一致,则需要更少地唤醒CPU。上例中的1ms
并不理想 – 我通常在sub-minute预定作业中将精度设置为1
(1秒),但这意味着如果查看显示”Hello World”消息的日志,您会发现它经常出现迟了1秒。如果您对此感到满意,我建议将精度设置为1秒或更长。
正如您可能已经注意到的那样,这个计时器并不能很好地模仿Cron – 从命令不会在每个挂钟时段开始时开始(即它不会在时钟的第10秒开始,那么20日等等)。相反,只是在计时器瘫痪时发生。如果系统在12:05:37启动,则下次命令运行时间为12:05:47,然后是12:05:57等。如果您对实际挂钟准确度感兴趣,那么您可以想要替换OnBootSec
和OnUnitActiveSec
字段,而是使用您想要的计划设置OnCalendar
规则(根据我的理解,使用日历格式不能超过1秒)。上面的例子也可以写成:
OnCalendar=*-*-* *:*:00,10,20,30,40,50
最后注意:正如您可能猜到的那样,helloworld.timer
单元启动helloworld.service
单元,因为它们具有相同的名称(减去单元类型后缀)。这是默认设置,但您可以通过为[Timer]
部分设置Unit
字段来覆盖它。
更多血腥细节可在以下网址找到:
-
Arch Linux Wiki page about SystemD timers通过示例给出了非常好的主题概述。
-
man systemd.timer
-
man systemd.time
-
man systemd.service
-
man system.exec