Celery: لا تقوم الدالة add_periodic_task بتشغيل المهمة

تم إنشاؤها على ١٣ نوفمبر ٢٠١٦  ·  33تعليقات  ·  مصدر: celery/celery

قائمة تدقيق

  • [x] لقد قمت بتضمين ناتج celery -A proj report في الإصدار.
    (إذا لم تكن قادرًا على القيام بذلك ، فعليك على الأقل تحديد الكرفس
    الإصدار المتأثر).
  • [x] لقد تحققت من وجود المشكلة في فرع الكرفس master .

خطوات التكاثر

مهام

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 نوفمبر 12؟ 00:00:00 / bin / sh / usr / sbin / rabbitmq-server

step2: تنفيذ المهام
python tasks.py
step3: ابدأ تغلب على العامل
celery -A tasks -l info beat
بدأ دقات الكرفس v4.0.0 (المكالمة الكامنة).
__ - ... __ - _
لوكال تايم -> 12-11-2016 17:37:58
التكوين ->
. وسيط -> amqp: // ضيف: ** localhost : 5672 //
. محمل -> celery.loaders.app.AppLoader
. المجدول -> الكرفس.نبض.جدول ثابت
. ديسيبل -> جدول الكرفس
. ملف السجل -> [stderr] @٪ INFO
. maxinterval -> 5.00 دقائق (300 ثانية)
فوز [2016-11-12 17: 37: 58،912: INFO / MainProcess]: جارٍ البدء ...

سلوك متوقع

أتوقع أن يقوم المجدول بتشغيل وظيفة add () كل عشر ثوان.

السلوك الفعلي

لا يتم تشغيل وظيفة add ().
لا أرى أي استثناء في المحطة. هل أفتقد أي شيء؟

Celerybeat Bug Report

التعليق الأكثر فائدة

لتشغيل المهام الدورية ، يجب عليك أيضًا استدعاء المجدول عند بدء تشغيل عامل باستخدام الخيار -B :

celery -A proj worker -B

عند استخدام الكرفس في تطبيقات django ، حيث يتم اكتشاف المهام تلقائيًا من التطبيقات ، تحتاج إلى استخدام إشارة on_after_finalize بدلاً من 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

مرحبًا ، لدي نفس المشكلة. لكني أحاول أن أبدأ الكرفس برمجيًا في خيط. ربما هذا هو السبب.

هذا هو خيطي:

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 أيضا وجود هذه المشكلة. خضعت واختبرت باستخدام

الكرفس: 4.0.2

لتشغيل المهام الدورية ، يجب عليك أيضًا استدعاء المجدول عند بدء تشغيل عامل باستخدام الخيار -B :

celery -A proj worker -B

عند استخدام الكرفس في تطبيقات django ، حيث يتم اكتشاف المهام تلقائيًا من التطبيقات ، تحتاج إلى استخدام إشارة on_after_finalize بدلاً من 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 لديه نفس المشكلة مع الكرفس (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.conf.beat_schedule بدلاً من add_periodic_task ديناميكيًا لحل هذه المشكلة ، نظرًا لأنني لست مضطرًا إلى ضبط الجدول بشكل ديناميكي ، ولكن ما زلت لا أعرف سبب حدوث هذه المشكلة.

دخلت في المكتبة ووجدت أنه تم إنشاء / إرفاق مستمع الإشارة الخاص بي بعد إطلاق إشارة on_after_configure . (كنت أضع مستمع الإشارة الخاص بي في app/tasks.py ولم يكن يعمل.)

لقد استنتجت أن إشارة الاستعداد لتطبيق Django من المحتمل أن يتم تنفيذها بعد تكوين Celery وهي تعمل بشكل جيد بالنسبة لي حتى الآن.

ملاحظة: لست متأكدًا مما يستلزمه تكوين الكرفس بالفعل وما إذا كان من الممكن أن يتم تشغيل هذا التطبيق قبل تكوين الكرفس ... ومع ذلك ، أتوقع أنه سيؤدي على الأقل إلى حدوث خطأ في وقت التشغيل.

نموذج رمز من 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) بالتحقق مما إذا كان الكرفس قد تم تكوينه بالفعل وإذا كان الأمر كذلك يتم تنفيذه على الفور و 2) إذا لم يتم تكوين الكرفس يضيف المستمع باستخدام @celery.on_after_configure.connect .

في الوضع الحالي ، تمثل المستندات مشكلة نظرًا لأن الكثير منا واجه هذه المشكلة.

CCingrustanacexdviennadd فقط حتى يمكنك محاولة إصلاح هذا إذا كنت لا تزال بحاجة إلى جدول المهام حيوي؟

بعد أن وضعت سنتي هناك ، شعرت بالضيق من هذا الأمر وانتهى بي الأمر إلى إعادة ترتيب بعض مهامي. لدينا حوالي 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 لمعرفة ما إذا كان ذلك سيؤدي إلى إصلاحه. لا نرد. ثم أمرت بهم حتى يطلق الجزء السفلي أولاً ويطلق الأعلى ثانيًا وينتهي الأمر بإصلاحه. بمعنى آخر:

@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 والكرفس 4.1.0.

كنت قادرا على جعل هذا العمل. تحقق من إجابتي هنا:

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

@ prasanna-balaraman يبدو أن هذا يعمل ، شكرًا لك على الاقتراح!

نفس المشكلة بالنسبة لي: سأختبر الحل الآخر: https://stackoverflow.com/a/41119054/6149867

إغلاق. إذا كان لا يزال يظهر وأي شخص لديه أي كود أو اقتراحات مستندات ، فلا تتردد في إرسال تقرير العلاقات العامة الذي يشير إلى هذه المشكلة.

لقد استغرق الأمر بعض الوقت لأدرك أنه في حالة ظهور أي استثناء في setup_periodic_tasks ، فسيتم قمعه بصمت.

الوظيفة تسمى هنا: https://github.com/celery/celery/blob/master/celery/app/base.py#L950

إذا حدث خطأ ما ، فسيتم حفظ الاستثناء فقط في الردود ، بدون إعادة رفع أو تسجيل:
https://github.com/celery/celery/blob/master/celery/utils/dispatch/signal.py#L276

لذا فإن اقتراحي هو إبقاء setup_periodic_tasks بسيطة قدر الإمكان.
أتمنى أن يساعدك هذا!

@ chiang831 هل لديك أي اقتراحات لتحسينه؟ إذا كان الأمر كذلك ، الرجاء إرسال العلاقات العامة أو فتح مناقشة حول القائمة البريدية لمستخدمي الكرفس

تحديدهم بـ 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 / gc والعمر الدقيق لوظائفك المزينة.

يحتوي Signal.connect بشكل افتراضي فقط على مرجع ضعيف لمعالج الإشارة. هذا أمر منطقي بالنسبة لحالات الاستخدام الأخرى لجسم الإشارة (كائن قصير العمر لا ينبغي أن يتم الاحتفاظ بإشارات الأسلاك بواسطة معالجات الإشارات الخاصة به) ، ولكنه مفاجئ جدًا في هذه الحالة.

كانت حالة الاستخدام الخاصة بي عبارة عن مصمم ديكور لتسهيل إضافة مهام دورية جديدة:

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_finalize بدلاً من 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 .

هذا يعمل لي بدلا من ذلك.

إذا كنت تحاول حل هذه المشكلة ، فأعد تشغيل محرك عامل الإرساء أولاً ، فقد يكون خطأ في نظام الإشارات

هل يجب إغلاق هذه المشكلة باعتبارها ليست خطأ؟

auvipy غير متأكد. يبدو أنه حشرة كرفس

إنه خطأ يجب أن نصلحه.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات