我有一个系统,其中一个 cron 作业用于manage.py
每分钟驱动一个命令。
问题是,这项工作有时可能需要一分钟以上的时间,同时运行两个命令实例是不安全的。
有没有一种好方法可以让命令检测自身的另一个实例是否已经在运行并提前退出?有没有更好的方法来达到同样的目的?
您还可以使用例如django-cronjobs(免责声明:我自己没有使用它)来注册工作。从文档:
# myapp/cron.py
import cronjobs
@cronjobs.register
def periodic_task():
pass
然后使用:
$ ./manage.py cron periodic_task
更重要的是:django-cronjob 甚至在默认情况下确保只有一个作业副本同时运行。
您可以做的是让命令在命令开头创建一个文件,然后再执行它的任务(包含作业的 pid),然后在命令结束时清理该文件。
当命令运行时,它应该首先检查该 pidfile 是否存在。如果是这样,它不应该执行它的工作。
所以:
它并不完美(例如,如果命令没有正确完成,pidfile 不会被删除并且命令永远不会再次运行),但它对于您的情况可能已经足够了。
另请参阅问题:pid 和 lock 文件是干什么用的?
我一直在使用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()
您可以使用 cronjob 库来处理锁定作业以防止多次执行 -防止多次执行
作为替代方案,您可以使用celerybeat
而不是cron
控制您的工作。Celerybeat
会带来更多开销,但如果您已经将 celery 作为应用程序的一部分,那么这应该不会太难。这列出了celerybeat
celerybeat 与 cron 相比有哪些优势?
您必须在某处保留状态以指示作业已在运行。该技术很好,但另一种方法是通过在缓存级别(Memcache/Redis)或直接在数据库中实现信号量pid
来使用信号量。当可能没有一致的文件系统可用于管理 pid 文件时,这尤其有用。例如。您正在 Heroku 上运行您的应用程序。
同样理想的是,如果可以的话,尽量使您的 cron 作业具有幂等性,即,即使作业并行运行多次,也不会产生副作用。