Celerybeat计划多次执行任务?

5 投票
1 回答
5875 浏览
提问于 2025-04-19 03:35

我有一个任务叫做 calculate_common_locations,它通过 CELERYBEAT_SCHEDULE 每次只运行一次。这个任务的主要功能就是调用数据库里的一个函数:

@app.task
def calculate_common_locations():
    db.execute("SELECT * FROM calculate_centroids('b')")

这是 CELERYBEAT_SCHEDULE 中的一个条目:

CELERYBEAT_SCHEDULE = {
   'common_locations': {
        'task': 'clients.tasks.calculate_common_locations',
        'schedule': crontab(hour=23, day_of_week='sun'), #every week
    },
    [..]
}

这个计划里还有其他一些任务,它们要么是 每天运行一次,要么是 每10秒运行一次。这些任务似乎并不会被重复运行很多次。但是,Celery flower 显示这个任务已经执行了超过20次。第一次按计划开始,运行大约100秒,成功后又重新开始了。

在这里输入图片描述

现在只有一个 celerybeat 在运行:

ps -Af | grep celerybeat 
foo     24359   779  0 01:53 ?        00:00:04 [celeryd: celery@celery:MainProcess] -active- (worker --beat --app=cloud.celeryapp:app --concurrency=10 -l INFO -s /home/foo/run/celerybeat-schedule --pidfile=/home/foo/run/celerybeat.pid)         

这是 celery 启动的方式(通过 supervisord):

celery worker --beat --app=cloud.celery app:app --concurrency=10 -l INFO -s /home/foo/run/celerybeat-schedule --pidfile=/home/foo/run/celerybeat.pid

我测试过不加 --concurrency=10 这个选项,数据库函数仍然被多次执行。

这个函数是从一个很大的表中读取数据(超过100万行),而且这个表经常被插入数据(每秒几次)。Postgres 的锁显示所有的锁都是被授予的。

有可能是因为查询在某个时刻终止,所以任务被重新运行吗?

在以下情况下没有问题:

  • 任务从 django shell 运行(直接运行或通过 .delay()),
  • 任务的内容被一个轻量级的 SQL 查询替换(select * from test),
  • 任务的内容被 sleep(100) 替换。

版本信息:

  • celery==3.1.12
  • psql (PostgreSQL) 9.3.5

1 个回答

10

如果你考虑一下 crontab(hour=23, day_of_week='sun') 的作用,可能会更容易理解:

>>> crontab(hour=23, day_of_week='sun')
<crontab: * 23 sun * * (m/h/d/dM/MY)>

这意味着这个任务会在每个星期天的晚上11点每分钟执行一次。

如果你想让它只在第一分钟执行,可以这样指定:

crontab(minute=0, hour=23, day_of_week='sun')

撰写回答