Celery: add_periodic_task関数はタスクをトリガーしません

作成日 2016年11月13日  ·  33コメント  ·  ソース: celery/celery

チェックリスト

  • [x] celery -A proj reportの出力を問題に含めました。
    (これができない場合は、少なくともセロリを指定してください
    影響を受けるバージョン)。
  • [x]この問題がCeleryのmasterブランチに対して存在することを確認しました。

再現する手順

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():
    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-サーバー

ステップ2:tasks.pyを実行します
python tasks.py
ステップ3:ビートワーカーを開始する
celery -A tasks -l info beat
セロリビートv4.0.0(latentcall)が始まります。
__ --... __ --_
LocalTime-> 2016-11-12 17:37:58
構成->
。 ブローカー-> amqp:// guest:** @localhost :5672 //
。 ローダー-> celery.loaders.app.AppLoader
。 スケジューラー-> celery.beat.PersistentScheduler
。 db-> celerybeat-スケジュール
。 ログファイル-> [stderr] @%INFO
。 maxinterval-> 5.00分(300秒)
[2016-11-12 17:37:58,912:INFO / MainProcess]ビート:開始中...

予想される行動

スケジューラーが10秒ごとにadd()関数をトリガーすることを期待しています。

実際の動作

add()関数はトリガーされません。
ターミナルに例外はありません。 私は何かが恋しいですか?

Celerybeat Bug Report

最も参考になるコメント

定期的なタスクを実行するには、 -Bオプションを使用してワーカーを起動するときにスケジューラーも呼び出す必要があります。

celery -A proj worker -B

タスクがアプリから自動検出されるdjangoアプリケーションでセロリを使用する場合は、 on_after_configure代わりにon_after_finalizeシグナルを使用する必要があります。

参照:
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

こんにちは、私は同じ問題を抱えています。 しかし、私はスレッドでプログラム的にセロリを始めようとしています。 多分それが原因です。

これは私のスレッドです:

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,
    },
}

on_after_configure.connectデコレータでsetup_periodic_tasks関数を使用する代わりに。

+1この問題もあります。

+1この問題もあります。
セロリバージョン4.0.2(潜在呼び出し)

+1この問題もあります。

+1この問題もあります。 @ liuallen1981のコードを

セロリ:4.0.2

定期的なタスクを実行するには、 -Bオプションを使用してワーカーを起動するときにスケジューラーも呼び出す必要があります。

celery -A proj worker -B

タスクがアプリから自動検出されるdjangoアプリケーションでセロリを使用する場合は、 on_after_configure代わりにon_after_finalizeシグナルを使用する必要があります。

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

-Bは本番用ではなく、少なくとも私の場合はすでに実行されているBeatsスケジューラーを起動するだけです。

セロリ(4.0.2)と同じ問題を抱えている+1

ここで同じ問題...

ビートサービスを開始するだけで、タスクを実行するワーカーも開始する必要があります。

+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)

これを解決するために、動的にadd_periodic_task celery.conf.beat_schedule代わりにCelery config

ライブラリをステップスルーしたところ、 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'
            )

また、 settings.py新しいAppConfigを使用するようにINSTALLED_APPSを指定する必要があることに注意してください。

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

良いアプローチまたは修正は、1)Celeryがすでに構成されているかどうかを確認し、構成されている場合はすぐに実行し、2)Celeryが構成されていない場合は、 @celery.on_after_configure.connectを使用してリスナーを追加する新しいデコレータを作成することです。

現状では、私たちの多くがこの問題に遭遇したため、ドキュメントには問題があります。

CCing @rustanacexd @viennaddは、タスクを動的にスケジュールする必要がある場合にこの修正を試すことができるようにするためですか?

私の2セントをそこに置いて、私はこれに少し気づき、私のタスクのいくつかを並べ替えなければならなくなった。 起動する予定のタスクが約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_bで上書きされるため、 do_thing_aが起動することはありません。 元々は両方とも5に設定されていましたが、発砲するのは1つだけ.1だけオフセットして、それが修正されるかどうかを確認することでした。 サイコロはありません。 それから私はそれらを注文して、低い方が最初に発砲し、高い方が次に発砲するようにしました。 すなわち:

@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()を使用していますが、これらはいくつかの作業として実行するのは謎のようなものですが、実行しないものもありますが、上記と同じ問題であると思われます。 これらの間隔は通常X時間/日ごとに発生するように設定されているため、完全には試していません。通常、それらが存在することを忘れています。

たぶん、この種の振る舞いはドキュメントに記載されているか、この振る舞いはあまり意味がありませんが、私は別のうさぎの穴を掘り下げます。 参考までに、RMQとcelery4.1.0の代わりにRedisを使用しています。

私はこの仕事をすることができました。 ここで私の答えを確認してください:

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

@ prasanna-balaramanそれはうまくいくようです、提案をありがとう!

私にとって同じ問題:私は別の解決策をテストします: https

閉鎖。 それでも表示され、コードやドキュメントの提案がある場合は、plzがこの問題を参照するPRを送信してください。

setup_periodic_tasksで例外が発生した場合、それがサイレントに抑制されることに気付くのに少し時間がかかりました。

関数はここで呼び出されます: https

何か問題が発生した場合、例外は応答にのみ保存され、再発生やログは記録されません。
https://github.com/celery/celery/blob/master/celery/utils/dispatch/signal.py#L276

したがって、私の提案は、setup_periodic_tasksをできるだけ単純に保つことです。
お役に立てれば!

@ chiang831それを改善するための提案はありますか? もしそうなら、plzはprを送るか、セロリユーザーのメーリングリストでディスカッションを開きます

on_after_finalizeそれらを定義することは、私にとってうまくいったことです(非djangoセロリアプリ)。

@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オブジェクト(シグナルをワイヤリングする短命のオブジェクトがシグナルハンドラによって存続されるべきではない)の他のユースケースには意味がありますが、この場合は非常に驚くべきことです。

私の特定のユースケースは、新しい定期的なタスクを簡単に追加できるようにするデコレータでした。

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アプリケーションでセロリを使用する場合は、 on_after_configure代わりにon_after_finalizeシグナルを使用する必要があります。

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

on_after_finalize使用すると、 app_name.celery.pyの最後でpython -m celery -A app_name worker -l info --autoscale=20,5 -BEプロセスがブロックされます。

@ liuallen1981と同じ設定と同じ問題。 誰もが何が起こっているのか理解していますか? 今のところ私は使用する必要があります

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

on_after_configure.connectデコレータでsetup_periodic_tasks関数を使用する代わりに。

これは代わりに私のために働きます。

この問題を解決しようとしている場合は、最初にDockerエンジンを再起動してください。これは、システムのバグを示している可能性があります。

この問題をバグではなくクローズする必要がありますか?

@auvipyわからない。 セロリのバグのようです

これは私たちが修正しなければならないバグです。

このページは役に立ちましたか?
0 / 5 - 0 評価