Celery: add_periodic_task函数不会触发任务

创建于 2016-11-13  ·  33评论  ·  资料来源: celery/celery

检查清单

  • [x]我已将celery -A proj report的输出包含在该问题中。
    (如果您无法执行此操作,请至少指定芹菜
    版本受影响)。
  • [x]我已验证Celery的master分支存在该问题。

重现步骤

task.py

from celery import Celery

celery = Celery('tasks', broker='pyamqp://guest@localhost//')

@celery.task
def add(x, y):
    return x + y


@celery.on_after_configure.connect
def add_periodic():
    celery.add_periodic_task(10.0, add.s(2,3), name='add every 10')

if __name__ == '__main__':
        add_periodic()


第1步:rabbitmq启动
rabbitmq 1186 1 0 Nov12吗? 00:00:00 / bin / sh / usr / sbin / rabbitmq-server

第二步:执行tasks.py
python tasks.py
第三步:开始击败工人
celery -A tasks -l info beat
芹菜节拍v4.0.0(latentcall)开始。
__-... __-_
LocalTime-> 2016-11-12 17:37:58
配置->
。 经纪人-> amqp:// guest:** @localhost :5672 //
。 loader-> celery.loaders.app.AppLoader
。 调度程序-> celery.beat.PersistentScheduler
。 db-> celerybeat-schedule
。 日志文件-> [stderr] @%INFO
。 maxinterval-> 5.00分钟(300s)
[2016-11-12 17:37:58,912:INFO / MainProcess]节拍:正在启动...

预期行为

我希望调度程序每十秒钟触发一次add()函数。

实际行为

add()函数不会被触发。
我没有在终端中看到任何异常。 我想念什么吗?

Celerybeat Bug Report

最有用的评论

要运行定期任务,使用-B选项启动工作程序时,您还必须调用调度程序:

celery -A proj worker -B

在Django应用程序中使用celery时(从应用程序自动发现任务),您需要使用on_after_finalize signal而不是on_after_configure

参考:
http://stackoverflow.com/questions/40712678/setup-periodic-task/40727526
http://stackoverflow.com/questions/41119053/connect-new-celery-periodic-task-in-django

所有33条评论

我有同样的问题 :(

您的示例对我来说效果很好。

注意:您的信号处理程序需要接受** kwargs,否则,将来会出现错误。

用你的例子

# file: tasks.py
from celery import Celery

celery = Celery('tasks', broker='pyamqp://guest@localhost//')

@celery.task
def add(x, y):
    return x + y


@celery.on_after_configure.connect
def add_periodic(**kwargs):
    celery.add_periodic_task(10.0, add.s(2,3), name='add every 10')

我按如下方式启动节拍服务:

$ celery -A tasks beat -l debug
celery beat v4.0.0 (latentcall) is starting.
__    -    ... __   -        _
LocalTime -> 2016-12-01 11:54:56
Configuration ->
    . broker -> amqp://guest:**<strong i="11">@localhost</strong>:5672//
    . loader -> celery.loaders.app.AppLoader
    . scheduler -> celery.beat.PersistentScheduler
    . db -> celerybeat-schedule
    . logfile -> [stderr]@%DEBUG
    . maxinterval -> 5.00 minutes (300s)
[2016-12-01 11:54:56,511: DEBUG/MainProcess] Setting default socket timeout to 30
[2016-12-01 11:54:56,511: INFO/MainProcess] beat: Starting...
[2016-12-01 11:54:56,517: DEBUG/MainProcess] Current schedule:
<ScheduleEntry: celery.backend_cleanup celery.backend_cleanup() <crontab: 0 4 * * * (m/h/d/dM/MY)>
<ScheduleEntry: add every 10 tasks.add(2, 3) <freq: 10.00 seconds>
[2016-12-01 11:54:56,517: DEBUG/MainProcess] beat: Ticking with max interval->5.00 minutes
[2016-12-01 11:54:56,528: DEBUG/MainProcess] Start from server, version: 0.9, properties: {'information': 'Licensed under the MPL.  See http://www.rabbitmq.com/', 'product': 'RabbitMQ', 'copyright': 'Copyright (C) 2007-2016 Pivotal Software, Inc.', 'capabilities': {'exchange_exchange_bindings': True, 'connection.blocked': True, 'authentication_failure_close': True, 'direct_reply_to': True, 'basic.nack': True, 'per_consumer_qos': True, 'consumer_priorities': True, 'consumer_cancel_notify': True, 'publisher_confirms': True}, 'cluster_name': 'rabbit<strong i="12">@grain</strong>', 'platform': 'Erlang/OTP', 'version': '3.6.4'}, mechanisms: [u'AMQPLAIN', u'PLAIN'], locales: [u'en_US']
[2016-12-01 11:54:56,531: INFO/MainProcess] Scheduler: Sending due task add every 10 (tasks.add)
[2016-12-01 11:54:56,534: DEBUG/MainProcess] using channel_id: 1
[2016-12-01 11:54:56,535: DEBUG/MainProcess] Channel open
[2016-12-01 11:54:56,537: DEBUG/MainProcess] beat: Synchronizing schedule...
[2016-12-01 11:54:56,537: DEBUG/MainProcess] tasks.add sent. id->af224838-cf72-4d0d-9076-1c39cdbeffb8
[2016-12-01 11:54:56,537: DEBUG/MainProcess] beat: Waking up in 9.97 seconds.
[2016-12-01 11:55:06,519: INFO/MainProcess] Scheduler: Sending due task add every 10 (tasks.add)
[2016-12-01 11:55:06,520: DEBUG/MainProcess] tasks.add sent. id->907cf307-e36f-455a-97a8-441c79b8ab92

嗨,我有同样的问题。 但是我尝试以编程方式在一个线程中启动celery。 也许是原因。

这是我的主题:

from __future__ import absolute_import, unicode_literals
import threading
from celery import current_app
from celery.bin import worker

app = current_app._get_current_object()


class CeleryThread(threading.Thread):
    def __init__(self):
        super(CeleryThread, self).__init__()

        self.app = app
        self.worker = worker.worker(app=self.app)

        self.options = {
            'broker': 'amqp://guest:guest<strong i="7">@localhost</strong>:5672//',
            'loglevel': 'INFO',
            'traceback': True,
        }

        app.add_periodic_task(5.0, test.s('hello'), name='add every 10')

    def run(self):
        self.worker.run(**self.options)


@app.task
def test(args1):
    print args1

和main.py来启动这个

celery_thread = CeleryThread()
# used to kill the thread when the main program stop
# celery_thread.daemon = True
celery_thread.start()

我的控制台输出是

 -------------- celery<strong i="14">@ubuntu</strong> v4.0.0 (latentcall)
---- **** ----- 
--- * ***  * -- Linux-4.4.0-51-generic-x86_64-with-Ubuntu-16.04-xenial 2016-12-03 14:33:10
-- * - **** --- 
- ** ---------- [config]
- ** ---------- .> app:         default:0x7f75775bfc50 (.default.Loader)
- ** ---------- .> transport:   amqp://guest:**<strong i="15">@localhost</strong>:5672//
- ** ---------- .> results:     disabled://
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery


[tasks]
  . kalliope.core.CrontabManager2.CeleryThread.test

[2016-12-03 14:33:10,458: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2016-12-03 14:33:10,466: INFO/MainProcess] mingle: searching for neighbors
[2016-12-03 14:33:11,486: INFO/MainProcess] mingle: all alone
[2016-12-03 14:33:11,515: INFO/MainProcess] celery<strong i="16">@ubuntu</strong> ready.

我会忘记选择吗? 我可以看到您在输出@ask中设置了“调度程序”

在此先感谢您的帮助。

@ liuallen1981相同的配置和相同的问题。 任何人都知道发生了什么事吗? 现在我必须使用

celery.conf.beat_schedule = {
    'do-something-periodically': {
        'task': 'tasks.my_task',
        'schedule': 3.0,
    },
}

而不是将setup_periodic_tasks函数与on_after_configure.connect装饰器一起使用。

+1也有这个问题。

+1也有这个问题。
芹菜版本4.0.2(latentcall)

+1也有这个问题。

+1也有这个问题。 继续使用@ liuallen1981的代码进行测试,并得到与我自己的代码相同的结果。

芹菜:4.0.2

要运行定期任务,使用-B选项启动工作程序时,您还必须调用调度程序:

celery -A proj worker -B

在Django应用程序中使用celery时(从应用程序自动发现任务),您需要使用on_after_finalize signal而不是on_after_configure

参考:
http://stackoverflow.com/questions/40712678/setup-periodic-task/40727526
http://stackoverflow.com/questions/41119053/connect-new-celery-periodic-task-in-django

-B不用于生产,而只是启动Beats调度程序,至少在我看来,该调度程序已在运行。

+1与Celery(4.0.2)有相同的问题

同样的问题在这里...

您只要启动节拍服务,还应该启动一个工作人员来完成任务。

+1

这里同样的问题

同样的问题

并且我尝试在回调中打印一些内容,似乎尚未调用该回调,但是RabbitMQ正常工作(当我在代码中触发任务时工作正常)

@celery.on_after_configure.connect
def setup_periodic_tasks(**kwargs):
    print('after connect')
(py35) ➜  celery -A celery.beat beat
celery beat v4.0.2 (latentcall) is starting.
__    -    ... __   -        _
LocalTime -> 2017-08-08 02:42:18
Configuration ->
    . broker -> amqp://**:**@**:5672//
    . loader -> celery.loaders.app.AppLoader
    . scheduler -> celery.beat.PersistentScheduler
    . db -> celerybeat-schedule
    . logfile -> [stderr]@%WARNING
    . maxinterval -> 5.00 minutes (300s)

我使用Celery config celery.conf.beat_schedule而不是动态add_periodic_task来解决此问题,因为我不必动态设置时间表,但仍然不知道为什么会发生此问题。

我遍历该库,发现在触发on_after_configure信号后,正在创建/附加我的信号侦听器。 (我将信号监听器放置在app/tasks.py ,但它不起作用。)

我认为Django的应用就绪信号可能会在Celery配置后执行,并且到目前为止对我来说效果很好。

注意:我不确定实际上需要什么celery配置以及在配置Celery之前是否有可能app.ready可以启动...但是,我希望它至少会引发运行时错误。

我的app/apps.py示例代码:

from django.apps import AppConfig
import django.db.utils
from celery_app import app as celery_app
from celery.schedules import crontab
import utils.cron


class MyAppConfig(AppConfig):
    name = 'app'
    verbose_name = "MyApp"

    def ready(self):
        print("MyAppConfig.ready invoked.")
        import app.signals

        print("* * * Setting up periodic tasks!")
        import app.models
        import app.tasks
        for cron in app.models.CronTask.objects.all():
            celery_app.add_periodic_task(
                crontab(**utils.cron.parse_crontab_expression_to_celery(cron.frequency)),
                app.tasks.do_cron.s(cron.id),
                name='do cron'
            )

请注意,您还需要将INSTALLED_APPS指向在AppConfig settings.py

INSTALLED_APPS = [
    # ...
    'app.apps.MyAppConfig',
]

一个好的方法或修补程序可能是编写一个新的装饰器,该装饰器将1)检查是否已配置Celery,如果立即配置,则立即执行; 2)如果未配置Celery,则使用@celery.on_after_configure.connect添加侦听器。

就目前而言,文档是有问题的,因为我们很多人都遇到了这个问题。

CCing @rustanacexd @viennadd只是这样,如果您仍然需要动态安排任务,可以尝试此修复程序?

把我的两分钱放在那里,我受了这一点,最终不得不重新安排我的一些任务。 我们大约有8个计划的任务应该触发,但是,我注意到会发生以下情况:

例子:

@celery.on_after_configure.connect
def setup_periodic_tasks(**kwargs):
    celery.add_periodic_task(5.0, do_thing_b.s(), name='Test B')
    celery.add_periodic_task(4.9, do_thing_a.s(), name='Test A')

像这样对它们进行排序意味着do_thing_a将永远不会触发,因为它将被do_thing_b覆盖。 最初它们都设置为5 ,尽管只有一个会触发(我相信在这种情况下,它会是B,因为它是第一个被添加的)。 接下来,我要做的是将其更改为小数,然后将其偏移.1以查看是否可以解决该问题。 没有骰子。 然后我命令他们,以便较低的首先射击,较高的第二次射击,最后修复它。 IE:

@celery.on_after_configure.connect
def setup_periodic_tasks(**kwargs):
    celery.add_periodic_task(4.9, do_thing_b.s(), name='Test B')
    celery.add_periodic_task(5.0, do_thing_a.s(), name='Test A')

我们还使用了一些crontab() s,尽管有些工作还是有些工作却让人迷惑不解,我怀疑这与上述问题相同。 我还没有完全解决这个问题,因为这些间隔通常设置为每X小时/天发生一次,所以我通常会忘记它们的存在。

也许在文档中提到了这种行为,或者我正陷入另一个困境,尽管这种行为没有多大意义。 作为参考,我们使用Redis代替RMQ和celery 4.1.0。

我能够完成这项工作。 在这里检查我的答案:

https://stackoverflow.com/a/46965132/560945

@ prasanna-balaraman似乎确实有效,谢谢您的建议!

对我来说同样的问题:我将测试另一个解决方案: https :

闭幕。 如果它仍然出现,并且任何人有任何代码或文档建议,plz随时发送引用此问题的消息。

我花了一段时间才意识到,如果setup_periodic_tasks中引发了任何异常,它将被静默地抑制。

该函数在此处调用: https :

如果发生任何错误,则仅将异常保存在响应中,而不会重新引发或记录:
https://github.com/celery/celery/blob/master/celery/utils/dispatch/signal.py#L276

因此,我的建议是使setup_periodic_tasks尽可能简单。
希望这可以帮助!

@ chiang831您对它有什么建议吗? 如果是这样,请发送公关或在celery-users邮件列表上打开讨论

on_after_finalize定义它们对我有用(非django celery应用程序)。

@app.on_after_finalize.connect
def app_ready(**kwargs):
    """
    Called once after app has been finalized.
    """
    sender = kwargs.get('sender')

    # periodic tasks
    speed = 15
    sender.add_periodic_task(speed, update_leases.s(),
        name='update leases every {} seconds'.format(speed))

只是碰到了这一点,以前的解决方案都没有对我有用。 导致这种情况的确切情况令人困惑,并且依赖于ref-counting / gc的行为以及修饰函数的确切生命周期。

默认情况下,Signal.connect仅持有对信号处理程序的弱引用。 这对于Signal对象的其他用例是有意义的(Signal对象的短寿命对象不应通过其信号处理程序使信号保持活动状态),但是在这种情况下非常令人惊讶。

我的特定用例是装饰器,可轻松添加新的定期任务:

def call_every_5_min(task):
    @app.on_after_configure.connect
    def register_task(sender, **_):
        sender.add_periodic_task(collect_every_m*60, task.signature())

<strong i="8">@call_every_5_min</strong>
<strong i="9">@task</strong>
def my_celery_task(_):
     pass

解决方法是显式地寻求强大的参考:

def call_every_5_min(task):
    def register_task(sender, **_):
        sender.add_periodic_task(collect_every_m*60, task.signature())
    app.on_after_configure.connect(register_task, weak=False)

文档中的示例在修饰后的函数位于模块或类范围内

我建议更改文档以传递weak=False ,这在上面列出的情况下应该可以使用。 我没有在Django上下文中对此进行显式测试。

要运行定期任务,使用-B选项启动工作程序时,您还必须调用调度程序:

celery -A proj worker -B

在Django应用程序中使用celery时(从应用程序自动发现任务),您需要使用on_after_finalize signal而不是on_after_configure

参考:
http://stackoverflow.com/questions/40712678/setup-periodic-task/40727526
http://stackoverflow.com/questions/41119053/connect-new-celery-periodic-task-in-django

我的过程python -m celery -A app_name worker -l info --autoscale=20,5 -BE受阻于的端app_name.celery.py当使用on_after_finalize

@ liuallen1981相同的配置和相同的问题。 任何人都知道发生了什么事吗? 现在我必须使用

celery.conf.beat_schedule = {
    'do-something-periodically': {
        'task': 'tasks.my_task',
        'schedule': 3.0,
    },
}

而不是将setup_periodic_tasks函数与on_after_configure.connect装饰器一起使用。

这对我有效。

如果您要解决此问题,请先重新启动Docker引擎,这可能是系统错误的信号

我们应该把这个问题当作不是bug来解决吗?

@auvipy不确定。 看起来是芹菜虫

这是我们必须修复的错误。

此页面是否有帮助?
0 / 5 - 0 等级