我有一个系统,每分钟都会使用一个cron作业来驱动manage.py
命令。
问题是,作业有时可能需要超过一分钟,并且命令的两个实例一次运行是不安全的。
是否有一种很好的方法可以使命令检测自身的另一个实例是否已经在运行并提前退出?有没有更好的方法来达到同样的目的?
答案 0 :(得分:1)
你也可以使用例如django-cronjobs(免责声明:我自己没有用它)来注册一份工作。来自文档:
# myapp/cron.py
import cronjobs
@cronjobs.register
def periodic_task():
pass
然后使用:
$ ./manage.py cron periodic_task
还有什么:django-cronjob甚至默认情况下确保只有一份作业同时运行。
答案 1 :(得分:0)
你可以做的是让命令在命令开始时创建一个文件,然后再执行它的任务(包含作业的pid),然后在命令末尾清理该文件。
运行该命令时,应首先检查该pidfile是否存在。如果是这样,就不应该执行它的工作。
所以:
它并不完美(例如,如果命令没有正确完成,pid文件不会被删除,命令也不会再次运行),但它可能对你的情况来说已经足够了。
答案 2 :(得分:0)
您可以使用负责锁定作业的cronjob库来防止多次执行 - Preventing multiple executions
作为替代方案,您可以使用celerybeat
代替cron
来控制您的工作。 Celerybeat
带来了更多的开销,但如果您已经将芹菜作为应用程序的一部分,那么这应该不会太难。这列出了celerybeat
What are the advantages of celerybeat over cron?
您必须在某处保持状态以指示作业已在运行。 pid
技术很好,但另一种方法是通过在缓存级别(Memcache / Redis)或直接在数据库中实现它来使用Semaphore。当可能没有可用于管理pid文件的一致文件系统时,这尤其有用。例如。您正在Heroku上运行您的应用程序。
同样理想情况下,如果可以的话,尽量使你的cron作业具有幂等性,即使作业并行运行多次,也没有副作用。
答案 3 :(得分:0)
我一直在使用lockfile,而且效果很好。
基本用法:
from lockfile import FileLock, AlreadyLocked, LockTimeout
lock = FileLock(lock_name)
try:
lock.acquire(LOCK_WAIT_TIMEOUT)
except AlreadyLocked:
logging.debug("lock already in place. quitting.")
return
except LockTimeout:
logging.debug("waiting for the lock timed out. quitting.")
return
logging.debug("acquired.")
# do stuff...
logging.debug("releasing lock...")
lock.release()