Celery: fungsi add_periodic_task tidak memicu tugas

Dibuat pada 13 Nov 2016  ·  33Komentar  ·  Sumber: celery/celery

Daftar Periksa

  • [x] Saya telah memasukkan keluaran dari celery -A proj report dalam terbitan.
    (jika Anda tidak dapat melakukan ini, setidaknya tentukan Celery
    versi terpengaruh).
  • [x] Saya telah memverifikasi bahwa masalah tersebut ada pada cabang Celery master .

Langkah-langkah untuk mereproduksi

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


langkah 1: rabbitmq sudah habis
kelincimq 1186 1 0 Nov12? 00:00:00 / bin / sh / usr / sbin / rabbitmq-server

step2: jalankan task.py
python tasks.py
step3: mulai pekerja pukulan
celery -A tasks -l info beat
seledri mengalahkan v4.0.0 (panggilan laten) dimulai.
__ - ... __ - _
LocalTime -> 2016-11-12 17:37:58
Konfigurasi ->
. broker -> amqp: // guest: ** @localhost : 5672 //
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> seledri-jadwal
. logfile -> [stderr] @% INFO
. maxinterval -> 5.00 menit (300s)
[2016-11-12 17: 37: 58.912: INFO / MainProcess] ketukan: Mulai ...

Perilaku yang diharapkan

Saya mengharapkan penjadwal untuk memicu fungsi add () setiap sepuluh detik.

Perilaku sebenarnya

Fungsi add () tidak dipicu.
Saya tidak melihat pengecualian apa pun di terminal. Apakah saya melewatkan sesuatu?

Celerybeat Bug Report

Komentar yang paling membantu

Untuk menjalankan tugas periodik, Anda juga harus memanggil penjadwal saat memulai pekerja menggunakan opsi -B :

celery -A proj worker -B

Saat menggunakan seledri dalam aplikasi django, di mana tugas ditemukan secara otomatis dari aplikasi, Anda perlu menggunakan sinyal on_after_finalize alih-alih on_after_configure .

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

Semua 33 komentar

Saya memiliki masalah yang sama :(

Teladan Anda bekerja dengan baik untuk saya.

CATATAN: Penangan sinyal Anda perlu menerima ** kwargs, jika gagal akan menjadi kesalahan di masa mendatang.

Menggunakan teladan Anda

# 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')

Saya memulai layanan beat sebagai berikut:

$ 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

Hai, saya memiliki masalah yang sama. Tetapi saya mencoba memulai seledri secara terprogram dalam satu utas. mungkin itu penyebabnya.

Ini utas saya:

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

Dan main.py untuk meluncurkan ini

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

Keluaran konsol saya adalah

 -------------- 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.

Apakah saya lupa suatu pilihan? Saya dapat melihat Anda memiliki set "scheduler" di output @ask

Terima kasih sebelumnya atas bantuan apa pun.

Konfigurasi yang sama dengan @ liuallen1981 dan masalah yang sama. Ada yang tahu apa yang terjadi?. Untuk saat ini saya harus menggunakan

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

alih-alih menggunakan fungsi setup_periodic_tasks dengan on_after_configure.connect penghias.

+1 Juga mengalami masalah ini.

+1 Juga mengalami masalah ini.
Celery versi 4.0.2 (panggilan laten)

+1 Juga mengalami masalah ini.

+1 Juga mengalami masalah ini. Pergi dan diuji dengan kode @ liuallen1981 dan mendapatkan hasil yang sama seperti dengan kode saya sendiri.

Seledri: 4.0.2

Untuk menjalankan tugas periodik, Anda juga harus memanggil penjadwal saat memulai pekerja menggunakan opsi -B :

celery -A proj worker -B

Saat menggunakan seledri dalam aplikasi django, di mana tugas ditemukan secara otomatis dari aplikasi, Anda perlu menggunakan sinyal on_after_finalize alih-alih on_after_configure .

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

-B bukan untuk produksi dan hanya memulai penjadwal Beats yang setidaknya dalam kasus saya sudah berjalan.

+1 mengalami masalah yang sama dengan Celery (4.0.2)

Masalah yang sama di sini ....

Anda baru saja memulai layanan beat, juga harus memulai pekerja untuk melakukan tugas.

+1

masalah yang sama di sini

masalah yang sama di sini,

dan saya mencoba mencetak sesuatu di dalam callback, tampaknya callback belum dipanggil, tetapi RabbitMQ berfungsi (berfungsi dengan baik ketika saya memicu tugas dalam kode)

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

Saya menggunakan konfigurasi Celery celery.conf.beat_schedule alih-alih secara dinamis add_periodic_task untuk mengatasi ini, karena saya tidak perlu mengatur jadwal secara dinamis, tetapi masih tidak tahu mengapa masalah ini terjadi.

Saya melangkah melalui perpustakaan dan menemukan bahwa pendengar sinyal saya dibuat / dilampirkan setelah sinyal on_after_configure dipecat. (Saya menempatkan pendengar sinyal saya di app/tasks.py dan tidak berfungsi.)

Saya beralasan bahwa sinyal siap aplikasi Django mungkin akan dijalankan setelah konfigurasi Celery dan sejauh ini bekerja dengan baik untuk saya.

CATATAN: Saya tidak yakin apa konfigurasi seledri sebenarnya dan apakah mungkin app.ready dapat diaktifkan sebelum Celery dikonfigurasi ... namun, saya berharap itu setidaknya akan menimbulkan kesalahan runtime.

Kode contoh dari 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'
            )

Perhatikan bahwa Anda juga perlu mengarahkan INSTALLED_APPS untuk menggunakan AppConfig di settings.py :

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

Pendekatan atau perbaikan yang baik mungkin akan menulis dekorator baru yang 1) memeriksa apakah Celery sudah dikonfigurasi dan jika demikian dijalankan segera dan 2) jika Celery tidak dikonfigurasi menambahkan pendengar menggunakan @celery.on_after_configure.connect .

Seperti berdiri, dokumen bermasalah karena begitu banyak dari kita mengalami masalah ini.

CCing @rustanacexd @viennadd supaya Anda dapat mencoba perbaikan ini jika Anda masih perlu menjadwalkan tugas secara dinamis?

Menempatkan dua sen saya di luar sana, saya mendapat sedikit oleh ini dan akhirnya harus mengatur ulang beberapa tugas saya. Kami memiliki sekitar 8 tugas terjadwal yang seharusnya diaktifkan, namun, saya perhatikan bahwa hal berikut akan terjadi:

Contoh:

@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')

Memesannya seperti ini berarti do_thing_a tidak akan pernah aktif, karena akan ditimpa oleh do_thing_b . Awalnya mereka berdua ditetapkan ke 5 , meskipun hanya satu yang akan menyala (saya percaya dalam kasus ini itu akan menjadi B seperti yang ditambahkan pertama). Selanjutnya yang saya lakukan adalah mengubahnya menjadi desimal dan mengimbanginya dengan .1 untuk melihat apakah itu akan memperbaikinya. Tidak ada dadu. Kemudian saya memerintahkan mereka sehingga yang lebih rendah akan menembak lebih dulu dan yang lebih tinggi akan menembak kedua dan akhirnya memperbaikinya. Yaitu:

@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')

Kami juga menggunakan beberapa crontab() s, meskipun itu semacam misteri untuk dijalankan karena beberapa pekerjaan dan beberapa tidak, saya curiga itu adalah masalah yang sama seperti di atas. Saya belum sepenuhnya bermain-main dengannya, karena interval tersebut umumnya diatur untuk terjadi setiap X jam / hari, jadi saya biasanya lupa bahwa mereka ada.

Mungkin perilaku semacam ini disebutkan dalam dokumentasi, atau saya akan masuk ke lubang kelinci yang berbeda, meskipun perilaku ini tidak masuk akal. Sebagai referensi, kami menggunakan Redis, bukan RMQ dan seledri 4.1.0.

Saya bisa membuat ini berhasil. Cek jawaban saya di sini:

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

@ prasanna-balaraman Sepertinya berhasil, terima kasih atas sarannya!

Masalah yang sama untuk saya: Saya akan menguji solusi lain: https://stackoverflow.com/a/41119054/6149867

penutupan. jika masih muncul dan ada yang memiliki saran kode atau dokumen, silakan kirimkan pr merujuk masalah ini.

Butuh beberapa saat bagi saya untuk menyadari bahwa jika ada pengecualian yang dimunculkan dalam setup_periodic_tasks, itu akan disembunyikan secara diam-diam.

Fungsi tersebut dipanggil di sini: https://github.com/celery/celery/blob/master/celery/app/base.py#L950

Jika ada yang salah, pengecualian hanya disimpan dalam tanggapan, tidak ada permintaan ulang atau log:
https://github.com/celery/celery/blob/master/celery/utils/dispatch/signal.py#L276

Jadi saran saya adalah untuk menjaga setup_periodic_tasks sesederhana mungkin.
Semoga ini membantu!

@ chiang831 apakah Anda punya saran untuk memperbaikinya? Jika ya, silakan kirim pr atau buka diskusi di milis pengguna seledri

Mendefinisikan mereka di on_after_finalize adalah apa yang berhasil untuk saya (aplikasi seledri non-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))

Baru saja mengalami ini dan tidak ada solusi sebelumnya yang berhasil untuk saya. Skenario persis yang menyebabkan hal ini membingungkan dan bergantung pada perilaku penghitungan ref / gc dan masa pakai yang tepat dari fungsi yang didekorasi.

Signal.connect secara default hanya memiliki referensi lemah ke penangan sinyal. Ini masuk akal untuk kasus penggunaan lain dari objek Signal (objek berumur pendek yang kabel sinyal tidak boleh ditahan oleh penangan sinyalnya), tetapi sangat mengejutkan dalam kasus ini.

Kasus penggunaan khusus saya adalah dekorator untuk memudahkan penambahan tugas berkala baru:

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

Cara mengatasinya adalah dengan secara eksplisit meminta referensi yang kuat:

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)

Contoh di dokumen hanya berfungsi jika fungsi yang didekorasi berada pada modul atau cakupan kelas, dalam hal ini modul atau kelas terus memiliki referensi yang kuat ke fungsi tersebut. Jika tidak, satu-satunya referensi yang kuat akan mati di akhir cakupan yang ditentukan di dalamnya.

Saya sarankan untuk mengubah dokumen agar melewati weak=False , yang seharusnya berfungsi dalam kasus yang tercantum di atas. Saya belum secara eksplisit menguji ini dalam konteks Django.

Untuk menjalankan tugas periodik, Anda juga harus memanggil penjadwal saat memulai pekerja menggunakan opsi -B :

celery -A proj worker -B

Saat menggunakan seledri dalam aplikasi django, di mana tugas ditemukan secara otomatis dari aplikasi, Anda perlu menggunakan sinyal on_after_finalize alih-alih on_after_configure .

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

Proses saya python -m celery -A app_name worker -l info --autoscale=20,5 -BE diblokir di akhir app_name.celery.py bila menggunakan on_after_finalize .

Konfigurasi yang sama dengan @ liuallen1981 dan masalah yang sama. Ada yang tahu apa yang terjadi?. Untuk saat ini saya harus menggunakan

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

alih-alih menggunakan fungsi setup_periodic_tasks dengan on_after_configure.connect penghias.

Ini bekerja untuk saya sebagai gantinya.

jika Anda mencoba menyelesaikan masalah ini, kemudian reboot mesin buruh pelabuhan Anda terlebih dahulu, mungkin itu adalah bug sistem sinyal

haruskah kita menutup masalah ini sebagai bukan bug?

@auvipy tidak yakin. Sepertinya itu kutu seledri

Ini adalah bug yang harus kita perbaiki.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat