celery -A proj report
dalam masalah ini.software -> celery:4.1.0 (latentcall) kombu:4.1.0 py:3.5.2
billiard:3.5.0.3 redis:2.10.5
platform -> system:Linux arch:64bit, ELF imp:CPython
loader -> celery.loaders.app.AppLoader
settings -> transport:redis results:redis://:**@****************
task_ignore_result: True
accept_content: {'pickle'}
result_serializer: 'pickle'
result_backend: 'redis://:********@************************'
task_serializer: 'pickle'
task_send_sent_event: True
broker_url: 'redis://:********@************************'
versi redis-server, keduanya 2.x dan 3.x
Halo, saya tidak yakin apa yang dapat menyebabkan masalah dan sudah mencoba mencari solusi serupa, tetapi sejauh ini tidak berhasil. Oleh karena itu membuka edisi di sini, semoga membantu
Masalahnya dijelaskan di sana juga (bukan oleh saya): https://github.com/andymccurdy/redis-py/issues/612
Sejauh ini pengalamannya, itu terjadi dalam kedua kasus, di mana backend terlibat dan tidak (berarti hanya ketika menelepon apply_async(...)
)
Pengecualian saat memanggil apply_async()
Pengecualian saat memanggil .get()
(juga yang ini memiliki int, bukan daftar)
Semoga membantu
Untuk tidak membuang kesalahan.
AttributeError: objek 'daftar' tidak memiliki atribut 'decode'
Terima kasih!
Juga, ada jejak tumpukan penuh, yang mencakup semua parameter
Ini sepertinya kondisi balapan di kumpulan koneksi Redis dari operasi pekerja bersamaan. Jenis kumpulan pekerja mana yang Anda gunakan? Saya pikir jika Anda menggunakan kolam prefork Anda tidak akan mengalami masalah ini. Beritahu saya apa hasilnya, jika Anda mencobanya.
Hai @georgepsarakis ,
terima kasih atas tanggapan Anda, tampaknya kami menjalankan prefork
ketika memeriksa output saat memulai seledri (yang berjalan di bawah systemd) saya mendapatkan output ini:
-------------- celery@autoscaled-dashboard-worker v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.4.0-45-generic-x86_64-with-Ubuntu-16.04-xenial 2017-11-04 20:41:15
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: worker:0x7f984dbcce48
- ** ---------- .> transport: redis://:**@**
- ** ---------- .> results: redis://:**@**
- *** --- * --- .> concurrency: {min=3, max=12} (prefork)
-- ******* ---- .> task events: ON
beberapa info lainnya:
celery multi start -A ... -E --autoscale=12,3 -Ofair
+ beberapa agrumen lain yang tidak begitu penting, semuanya ditentukan sebagai layanan Type=forking
)beri tahu saya jika saya dapat menambahkan hal lain, ingin membantu sebanyak mungkin untuk menyelesaikannya :)
Terima kasih!
hal lain (meskipun saya tidak yakin apakah itu bisa terkait) - terkadang kami mendapatkan pengecualian ini (pengaturan yang sama seperti di atas)
File "/usr/local/lib/python3.5/dist-packages/celery/app/base.py", line 737, in send_task
amqp.send_task_message(P, name, message, **options)
File "/usr/lib/python3.5/contextlib.py", line 77, in __exit__
self.gen.throw(type, value, traceback)
File "/usr/local/lib/python3.5/dist-packages/kombu/connection.py", line 419, in _reraise_as_library_errors
sys.exc_info()[2])
File "/usr/local/lib/python3.5/dist-packages/vine/five.py", line 178, in reraise
raise value.with_traceback(tb)
File "/usr/local/lib/python3.5/dist-packages/kombu/connection.py", line 414, in _reraise_as_library_errors
yield
File "/usr/local/lib/python3.5/dist-packages/celery/app/base.py", line 736, in send_task
self.backend.on_task_call(P, task_id)
File "/usr/local/lib/python3.5/dist-packages/celery/backends/redis.py", line 189, in on_task_call
self.result_consumer.consume_from(task_id)
File "/usr/local/lib/python3.5/dist-packages/celery/backends/redis.py", line 76, in consume_from
self._consume_from(task_id)
File "/usr/local/lib/python3.5/dist-packages/celery/backends/redis.py", line 82, in _consume_from
self._pubsub.subscribe(key)
File "/usr/local/lib/python3.5/dist-packages/redis/client.py", line 2482, in subscribe
ret_val = self.execute_command('SUBSCRIBE', *iterkeys(new_channels))
File "/usr/local/lib/python3.5/dist-packages/redis/client.py", line 2404, in execute_command
self._execute(connection, connection.send_command, *args)
File "/usr/local/lib/python3.5/dist-packages/redis/client.py", line 2408, in _execute
return command(*args)
File "/usr/local/lib/python3.5/dist-packages/redis/connection.py", line 610, in send_command
self.send_packed_command(self.pack_command(*args))
File "/usr/local/lib/python3.5/dist-packages/redis/connection.py", line 585, in send_packed_command
self.connect()
File "/usr/local/lib/python3.5/dist-packages/redis/connection.py", line 493, in connect
self.on_connect()
File "/usr/local/lib/python3.5/dist-packages/redis/connection.py", line 567, in on_connect
if nativestr(self.read_response()) != 'OK':
File "/usr/local/lib/python3.5/dist-packages/redis/connection.py", line 629, in read_response
raise response
kombu.exceptions.OperationalError: only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context
kami mencoba memperbarui py-redis (akan melihat, tetapi hanya yang kecil)
setiap petunjuk sangat dihargai :)
@Twista dapatkah Anda mencoba tambalan di backend Redis?
Jika Anda dapat menambahkan di sini kode berikut:
def on_after_fork(self):
logger.info('Resetting Redis client.')
del self.backend.client
Saya harap ini akan memaksa properti yang di-cache klien untuk menghasilkan klien Redis baru setelah setiap fork pekerja.
Beri tahu saya jika ini ada hasilnya.
Hai, maaf lama responnya.
Hanya tindak lanjut - kami baru saja menambalnya dan akan melihat apakah itu membantu. Semoga secepatnya :)
terimakasih atas bantuannya :)
beri tahu kami tanggapan Anda
Hai,
Saya mengalami masalah yang hampir sama (menggunakan Celery.send_task
) dan memiliki pertanyaan terkait:
Mengapa, ketika memanggil tugas async (sehingga hasilnya tidak diharapkan ), Celery mulai mendengarkan penerbit redis ( self._pubsub.subscribe(key)
dipanggil oleh penangan sinyal celery/backends/redis.py
, baris 189, di on_task_call
)?
@georgepsarakis sayangnya tambalannya tidak membantu. :-(
di sini adalah jejak tumpukan lain:
Tolong beri tahu saya jika Anda ingin beberapa log atau tambalan lain diuji.
@wimby terima kasih banyak atas umpan baliknya. Bisakah Anda memberi tahu saya opsi apa yang Anda gunakan untuk memulai pekerja?
Hai @georgepsarakis
Akan menjawab yang ini alih-alih @wimby
itu seluruh perintah yang kami gunakan untuk memulai seledri
celery multi start worker -A ... --pidfile=... --logfile=... --loglevel=... -E --time-limit=300 --autoscale=10,3 --queues=... -Ofair
dihadapkan dengan masalah yang sama ketika memutuskan untuk mencoba redis broker, digulung kembali ke kelinci untuk saat ini..
Ada pembaruan tentang ini? Menjalankan ini dengan pengaturan yang mirip dengan @Twista / @wimby di mana kami memiliki pekerja cron yang berjalan di mesin terpisah dari proses yang menjadwalkan tugas kami.
seledri==4.0.2
redis==2.10.5.
Untuk memperjelas, ini terjadi pada mesin yang mengirim tugas, bukan mesin pekerja.
Saya melihat ini juga. Seledri 4.2.0, kombu 4.2.1, redis 2.10.6. Menggunakan redis untuk broker dan hasilnya. Lalu lintas redis berjalan di antara server melalui koneksi stunnel terenkripsi melalui port.
Menjalankannya dalam Django 1.11 yang berjalan pada mod_wsgi (2 proses, masing-masing 15 utas), dan itu tidak hanya terbatas pada pengecualian di atas. Saya tidak dapat menyalin-menempel jejak tumpukan penuh. Aplikasi memuat halaman web dengan sekelompok permintaan ajax (90ish per pemuatan halaman), yang masing-masing menjalankan tugas latar belakang melalui seledri. Tugas selesai dengan sukses, tetapi mendapatkan hasilnya kembali sulit.
Saat mengirimkan tugas, saya mendapatkan ConnectionError
s, AttributeError
s (daftar tidak memiliki enkode atribut).
Ketika mendapatkan hasilnya kembali, saya mendapatkan InvalidResponse
, ResponseError
, ValueError
, AttributeError
, TypeError
, IndexError
, hampir semuanya dari redis. Saya juga melihat kesalahan dekode dari kombu ketika mencoba mengurai respons json. Saya menduga lalu lintas bercampur di antara permintaan - dalam beberapa kasus saya telah melihat apa yang tampak seperti tanggapan parsial.
Saya beralih kembali untuk melakukan tugas-tugas yang lebih besar, yang setidaknya harus meminimalkan hal ini terjadi. Namun, saya telah melihat kasus di mana masalah protokol masih akan terjadi ketika bebannya minimal. Saya tidak akan terkejut jika ini disebabkan oleh masalah jaringan yang mendasarinya. Saya juga menambahkan logika coba lagi untuk mengirimkan permintaan.
@deterb jika Anda menetapkan task_ignore_result
dalam konfigurasi seledri Anda, ini akan mencegah hal ini terjadi. Kecuali Anda peduli dengan hasil tugas, dalam hal ini jelas tidak akan membantu.
Perbaikan untuk menghormati ignore_result
saat menjadwalkan tugas dibuat di 4.2.0, jadi Anda harus baik-baik saja.
@asgoel Intinya adalah untuk mendapatkan hasil untuk sebagian besar permintaan (tidak begitu banyak berjalan di latar belakang untuk mereka, tetapi menjalankan perhitungan berat pada server yang dibuat untuk itu alih-alih server web). Saya akan menambahkan hasil abaikan untuk yang lain dan melihat apakah itu membantu.
@deterb ini terdengar seperti masalah dengan operasi yang tidak aman untuk utas. Apakah mungkin untuk mencoba tidak menggunakan multithreading?
@georgepsarakis Saya setuju bahwa kedengarannya seperti masalah multithreading. Saya akan mencoba mengonfigurasi mod_wsgi agar berjalan dengan 15 proses, 1 utas per proses dan melihat apakah saya masih melihat perilaku itu. Saya tidak melakukan threading atau multiprocessing tambahan di luar mod_wsgi. Saya melihat perilaku serupa (meskipun dengan frekuensi yang lebih sedikit) berjalan dengan runserver Django. Satu-satunya antarmuka dengan klien redis di aplikasi web adalah melalui Celery, yaitu pengiriman tugas dan pengambilan hasilnya. redis-py mengklaim sebagai thread-safe.
Saya akan mencoba melakukan lebih banyak pengujian besok, dan melihat apakah saya dapat membuat ulang di luar Django dan tanpa proxy stunnel.
@georgepsarakis Saya tidak mendapatkan kesempatan untuk mencoba hari ini, tapi saya percaya #4670 (yaitu objek PubSub
dibagikan tidak menjadi thread safe) terkait, bersama dengan #4480. Sepertinya apa yang saya lihat terpisah dari tiket asli dan masalah lain yang disebutkan. Meskipun mungkin terkait dengan masalah yang diangkat @asgoel , saya pikir tiket terpisah untuk masalah konkurensi dengan backend hasil redis akan sesuai (tetap #4480 terkait dengan backend hasil RPC). Saya dapat mulai menarik bagian yang relevan dari jejak tumpukan juga.
Hai teman-teman, saya sering menghadapi kesalahan ini.
Saya menggunakan AWS Elasticache dan aplikasi saya diterapkan di AWS Elastic Beanstalk.
Kami mengubah AWS Elasticache menjadi Redis Labs dan kami meningkatkan batas waktu AWS Elastic Load Balancer menjadi 180-an dan server Apache menjadi 180-an juga.
Kesalahan berkurang banyak.
Namun demikian mereka masih terjadi dari waktu ke waktu. Oleh karena itu saya memutuskan untuk mengubah hasil backend ke PostgreSQL dan kemudian kesalahannya hilang sepenuhnya.
Hal yang menarik: kami mulai mengalami masalah ini setelah menerapkan rilis baru yang
Jadi, menarik untuk mengetahui ini mungkin sesuatu yang bergantung pada versi python. Berharap ini dapat membantu melacak masalah.
(Selebihnya, kami menggunakan seledri 4.2.1 dan redis 2.10.6)
Juga, tugas bermasalah diluncurkan oleh Celery beat, dan kami memiliki masalah yang sama dalam tugas yang diluncurkan oleh tugas lain
Terima kasih atas umpan balik semua orang. Hanya untuk memperjelas beberapa hal:
ResultConsumer
adalah komponen Redis Backend yang secara asinkron mengambil hasilnyaResultConsumer
menginisialisasi instance PubSub
ResultConsumer
dapat dibuat baik pada pekerja (alur kerja Kanvas) atau saat Tugas diantrekan dan hasilnya tidak diabaikanPubSub
tidak dapat digunakan secara bersamaan dari beberapa utasSaya tidak mengetahui apakah operasi yang sesuai dapat dilakukan pada startup Django, mungkin callback ini dapat membantu; memanggil ResultConsumer.on_after_fork
kemudian akan membuat instance baru dan masalah kemungkinan besar tidak akan terjadi.
Hmm.
Dalam kasus saya, saya telah mencoba mereproduksi masalah dengan meningkatkan frekuensi pada tugas di Celery Beat. Saat ini saya memiliki sesuatu seperti 1 kegagalan setiap 15 tugas, tetapi kegagalan terjadi pada pekerja, bukan di Beat, dan pekerja saya memiliki concurrency
dari 1 (Saya memiliki beberapa proses independen, tetapi semuanya "tunggal" ). htop
memberi tahu saya bahwa ada proses utama dengan satu utas anak. Apakah itu konsisten dengan hipotesis Anda?
Jika saya memahami dengan benar jawaban Anda (saya membaca ulang, hanya untuk memastikan), paragraf:
Saya tidak mengetahui apakah operasi yang sesuai dapat dilakukan pada startup Django, mungkin panggilan balik ini dapat membantu; memanggil ResultConsumer.on_after_fork kemudian akan membuat instance baru dan masalah kemungkinan besar tidak akan terjadi.
ini akan terkait dengan kasus di mana kami akan memiliki kesalahan saat menerbitkan tugas dari proses web kami (gunicorn/uwsgi/...), kan?
sejauh menyangkut Pekerja, perubahan ini harus mencakup kasus memulai garpu baru
Dalam kasus kami, kesalahan tersebut berasal dari pekerja secara eksklusif dengan Seledri 4.2.1. Jika saya memahami pernyataan Anda dengan benar, maka, mungkin masih ada masalah di sana ...
Di Celery 4.2.0, saya dapat mengatasi masalah ini dengan melakukan hal berikut:
result.backend.result_consumer.cancel_for(result.task_id)
result.backend.result_consumer.stop()
Saya belum menemukan cara untuk menghapus panggilan untuk berhenti; jika saya menghapusnya koneksi mulai bocor (perhatikan saya menjalankan di lingkungan mod_wsgi yang terhubung ke redis over stunnel; akhirnya mendapatkan masalah koneksi setelah beberapa ratus permintaan). Setelah beberapa saat saya berhenti bisa terhubung melalui terowongan. Saya juga belum menemukan cara untuk terhubung ke manajemen utas mod_wsgi.
Kasus uji yang saya gunakan memiliki halaman web yang membuat ~1500 Ajax meminta 5 sekaligus berjalan seluruhnya dalam perintah run_server Django. Tanpa batas kecepatan, kondisi balapan pada objek pubsub backend hasil terjadi terus-menerus. Mereka terjadi secara teratur dengan tingkat yang membatasi juga.
Saya menduga menggunakan utas ResultConsumers lokal untuk redis dapat membantu dengan masalah pekerja Greenlet juga, meskipun saya tidak yakin bagaimana cara menutup pubsubs dengan andal.
Mengalihkan RedisBackend ke menggunakan polling untuk aplikasi web berfungsi tanpa perubahan khusus aplikasi. Saya menukar mixin backend async dengan base.SyncBackendMixin dan mengomentari baris yang merujuk pada konsumen hasil. Sampai solusi yang lebih bersih diperbaiki, saya mungkin akan mengganti aplikasi web untuk menggunakan versi SyncBackend dari RedisBackend dan membiarkan para pekerja menggunakan yang normal (yang tampaknya tidak memiliki masalah ini.
Mengingat saya menggunakan Django, solusi saya adalah menggunakan Django-celery-results. Ini lebih sejalan dengan keputusan desain lain untuk menggunakan redis lebih sedikit, dan kami sebenarnya tidak menyimpan banyak. Kami belum memasukkannya ke dalam produksi.
Hasilnya cukup berat dan transitif saya tidak ingin memasukkannya ke dalam database. Sebagai opsi yang lebih konservatif, saya mungkin langsung menyimpan hasilnya daripada membiarkan Seledri melakukannya sampai ini diperbaiki (saya sudah menggunakan Redis untuk beberapa caching).
Saya mengalami masalah serupa dengan ini. Saya harap informasi tambahan yang saya berikan dapat menjelaskan lebih banyak masalah.
Saya memiliki satu pekerja seledri (konkurensi=1) dan server yang mendorong tugas ke antrian dan mengambil hasilnya. Saya menggunakan rabbitmq sebagai broker dan redis untuk backend hasil.
Saya menggunakan seledri 4.2.1 & hireis 0.2.0 (masalahnya terjadi tanpa hire juga).
Memanggil layanan pada kecepatan yang lebih lambat berfungsi sebagaimana dimaksud, tetapi begitu saya mengirim ~100 permintaan bersamaan, saya mulai melihat masalah yang telah dijelaskan dalam masalah ini. Saya memiliki beberapa pengecualian berbeda, yang saya yakin semuanya terkait.
File "/___/___/celery_app.py", line 101, in send_task
task_result.wait(timeout=timeout, propagate=True)
File "/usr/lib/python3.6/site-packages/celery/result.py", line 224, in get
on_message=on_message,
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 188, in wait_for_pending
for _ in self._wait_for_pending(result, **kwargs):
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 255, in _wait_for_pending
on_interval=on_interval):
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 56, in drain_events_until
yield self.wait_for(p, wait, timeout=1)
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 65, in wait_for
wait(timeout=timeout)
File "/usr/lib/python3.6/site-packages/celery/backends/redis.py", line 119, in drain_events
m = self._pubsub.get_message(timeout=timeout)
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2260, in get_message
response = self.parse_response(block=False, timeout=timeout)
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2183, in parse_response
return self._execute(connection, connection.read_response)
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2176, in _execute
return command(*args)
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 579, in read_response
self.disconnect()
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 530, in disconnect
self._sock.close()
AttributeError: 'NoneType' object has no attribute 'close'
Dan
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 344, in read_response
bufflen = self._sock.recv_into(self._buffer)
OSError: [Errno 9] Bad file descriptor
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2165, in _execute
return command(*args)
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 577, in read_response
response = self._parser.read_response()
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 357, in read_response
(e.args,))
redis.exceptions.ConnectionError: Error while reading from socket: (9, 'Bad file descriptor')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 577, in read_response
response = self._parser.read_response()
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 362, in read_response
response = self._reader.gets()
redis.exceptions.InvalidResponse: Protocol error, got "t" as reply type byte
Dan
File "/usr/lib/python3.6/site-packages/celery/result.py", line 224, in get
on_message=on_message,
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 188, in wait_for_pending
for _ in self._wait_for_pending(result, **kwargs):
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 255, in _wait_for_pending
on_interval=on_interval):
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 56, in drain_events_until
yield self.wait_for(p, wait, timeout=1)
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 65, in wait_for
wait(timeout=timeout)
File "/usr/lib/python3.6/site-packages/celery/backends/redis.py", line 119, in drain_events
m = self._pubsub.get_message(timeout=timeout)
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2260, in get_message
response = self.parse_response(block=False, timeout=timeout)
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2183, in parse_response
return self._execute(connection, connection.read_response)
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2176, in _execute
return command(*args)
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 577, in read_response
response = self._parser.read_response()
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 359, in read_response
self._reader.feed(self._buffer, 0, bufflen)
AttributeError: 'NoneType' object has no attribute 'feed'
Dari sudut pandang pekerja seledri, semua tugas ini berhasil dan tidak ada pengecualian yang dikirim kembali. Saya menerima pengecualian ini dari proses Python yang mencoba mengambil hasil tugas.
Apakah ada pembaruan tentang masalah ini, atau kemungkinan solusi yang harus saya coba tidak tercantum dalam masalah ini?
Apakah Anda menjalankan dengan banyak utas? Jika demikian, Anda agak cocok dengan pengaturan Django yang saya sebutkan sebelumnya. Jika tidak, itu mungkin sesuatu yang lain.
Solusi saya saat ini adalah tidak pernah benar-benar menggunakan objek hasil yang kembali dan sebaliknya mendorong dan menarik hasilnya langsung ke/dari struktur data Redis. Karena permintaan web memblokir hasil, saya biasanya akan memberikan "daftar" hasil untuk tugas untuk memasukkan tanggapan dan memasukkan daftar itu ke dalam permintaan web. Saya akan menggunakan blpop redis untuk mendapatkan hasilnya kembali sampai saya memiliki semuanya atau waktu habis pada yang terakhir. Saya menggunakan tanda abaikan hasil saat mengirimkan tugas untuk mencegah saluran pendengar dibuat, dan masih akan menyimpan tugas asli untuk mencatat id dan berpotensi mendapatkan status kembali nanti.
Saya tidak merasa nyaman berjalan dengan patch yang saya sebutkan sebelumnya; Saya membutuhkan sesuatu yang saya tahu tidak akan memiliki potensi efek samping.
@deterb Terima kasih atas tanggapannya.
Saya menjalankan dengan banyak utas, jadi saya yakin ini sangat mirip dengan apa yang Anda lihat. Saya berpotensi melakukan sesuatu yang serupa dengan utas tambahan yang pada dasarnya polling redis untuk hasil, tetapi saya benar-benar ingin membahasnya juga.
Saya melanjutkan dan mengumpulkan beberapa wadah buruh pelabuhan untuk mereproduksi bug dengan pengaturan yang cukup sederhana
https://github.com/sihrc/celery_repro. Saya akan terus memeriksanya sendiri melalui repo ini, tetapi sejauh ini saya tidak menemukan apa pun. Ini akan membawa saya sedikit untuk mendapatkan kecepatan dengan seluk-beluk seledri dan redis.
Traceback (most recent call last):
File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/app/celery_race_condition/app.py", line 21, in <module>
results = [result.result() for result in futures]
File "/app/celery_race_condition/app.py", line 21, in <listcomp>
results = [result.result() for result in futures]
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 432, in result
return self.__get_result()
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
File "/usr/lib/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "/app/celery_race_condition/app.py", line 11, in call_and_retrieve
async_result.wait(timeout=100, propagate=True)
File "/usr/lib/python3.6/site-packages/celery/result.py", line 224, in get
on_message=on_message,
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 188, in wait_for_pending
for _ in self._wait_for_pending(result, **kwargs):
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 255, in _wait_for_pending
on_interval=on_interval):
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 56, in drain_events_until
yield self.wait_for(p, wait, timeout=1)
File "/usr/lib/python3.6/site-packages/celery/backends/async.py", line 65, in wait_for
wait(timeout=timeout)
File "/usr/lib/python3.6/site-packages/celery/backends/redis.py", line 119, in drain_events
m = self._pubsub.get_message(timeout=timeout)
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2513, in get_message
response = self.parse_response(block=False, timeout=timeout)
File "/usr/lib/python3.6/site-packages/redis/client.py", line 2428, in parse_response
if not block and not connection.can_read(timeout=timeout):
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 618, in can_read
return self._parser.can_read() or \
File "/usr/lib/python3.6/site-packages/redis/connection.py", line 372, in can_read
self._next_response = self._reader.gets()
redis.exceptions.InvalidResponse: Protocol error, got "\r" as reply type byte
Saya telah melakukan debugging sejak dan saya menemukan bahwa segera setelah utas yang telah digunakan sebelumnya digunakan lagi untuk mengambil hasil, kami mulai mendapatkan kesalahan. Saya menguji ini dengan membuat kumpulan utas 100 dan menjalankan 101 tugas secara bersamaan.
Bagi saya itu telah bermuara pada keamanan utas dari ResultConsumer dan mungkin klien PubSub redis. Solusi saya saat ini menggunakan ResultConsumer terpisah per konteks lokal utas.
import threading
from celery.backends.redis import RedisBackend
local_context = threading.local()
class Backend(RedisBackend):
<strong i="7">@property</strong>
def result_consumer(self):
consumer = getattr(local_context, "consumer", None)
if consumer:
return consumer
local_context.consumer = self.ResultConsumer(
self, self.app, self.accept,
self._pending_results, self._pending_messages,
)
return local_context.consumer
@result_consumer.setter
def result_consumer(self, value):
local_context.consumer = value
Celery(
...,
result_backend=__name__ + ".Backend",
...
)
Sayangnya, saya tidak bisa menggali cukup untuk mencari tahu mengapa ini menjadi masalah untuk memulai, tetapi mudah-mudahan, solusi ini berguna untuk orang lain.
Seledri cukup agresif dalam mendaftarkan saluran di antarmuka PubSub, yang menurut dokumentasi redis-py
Solusi yang Anda posting memiliki tema yang sama dengan yang saya lakukan, meskipun terlihat lebih bersih.
@sihrc @deterb Saya pikir Anda berada di jalur yang benar, ini dapat dikaitkan dengan klien PubSub yang tidak aman untuk thread. @sihrc menggunakan utas lokal untuk tujuan ini tampaknya benar bagi saya, apakah Anda mungkin mempertimbangkan/mencoba mentransfer logika ke ResultConsumer
dan contoh klien PubSub
? Either way jika Anda bisa memberikan PR dengan solusi ini akan sangat bagus!
@georgepsarakis Saya telah mencoba untuk memindahkan logika ke ResultConsumer dan melemparkannya ke PR. Penafian total: Saya tidak yakin apakah saya punya waktu untuk secara aktif mendorong PR ini tepat waktu, tetapi saya akan melakukan yang terbaik.
@sihrc terima kasih! Itu sangat bisa dimengerti, beri tahu kami jika Anda tidak dapat mendedikasikan lebih banyak waktu kapan pun.
Sepertinya PR untuk solusinya tidak aktif. Apakah ada niat untuk memperbaiki masalah ini?
Mungkin setelah rilis.
@thedrow Terima kasih atas tanggapan cepatnya. Apakah Anda mengatakan setelah 4.3 dirilis (semoga bukan 5.0), kontributor akan mengalihkan perhatian mereka ke bug ini?
Ya.
Kami juga telah melihat ini pada versi 4.2 baru-baru ini dalam sebulan terakhir.
@thedrow apakah Anda memiliki perkiraan kasar tentang timeline untuk rilis 4.3?
4.3 dirilis kembali pada bulan Maret. juga, 4.4rc2 ada di pypi dan 4.4 akan dirilis minggu ini.
@auvipy oh bagus, terima kasih. Apakah masalah ini saat ini sedang ditangani?
tidak yakin tetapi direncanakan untuk 4,5.
FWIW, bahkan dengan potongan kode di atas , kami masih melihat Kesalahan Protokol berkala, meskipun lebih jarang:
Traceback (most recent call last):
File "/opt/python/current/app/app/XXXX", line #, in _check_celery
result = async_result.get(timeout=self.service_timeout)
File "/opt/python/run/venv/local/lib/python3.6/site-packages/celery/result.py", line 226, in get
on_message=on_message,
File "/opt/python/run/venv/local/lib/python3.6/site-packages/celery/backends/asynchronous.py", line 188, in wait_for_pending
for _ in self._wait_for_pending(result, **kwargs):
File "/opt/python/run/venv/local/lib/python3.6/site-packages/celery/backends/asynchronous.py", line 255, in _wait_for_pending
on_interval=on_interval):
File "/opt/python/run/venv/local/lib/python3.6/site-packages/celery/backends/asynchronous.py", line 56, in drain_events_until
yield self.wait_for(p, wait, timeout=1)
File "/opt/python/run/venv/local/lib/python3.6/site-packages/celery/backends/asynchronous.py", line 65, in wait_for
wait(timeout=timeout)
File "/opt/python/run/venv/local/lib/python3.6/site-packages/celery/backends/redis.py", line 127, in drain_events
message = self._pubsub.get_message(timeout=timeout)
File "/opt/python/run/venv/local/lib/python3.6/site-packages/redis/client.py", line 3297, in get_message
response = self.parse_response(block=False, timeout=timeout)
File "/opt/python/run/venv/local/lib/python3.6/site-packages/redis/client.py", line 3185, in parse_response
response = self._execute(conn, conn.read_response)
File "/opt/python/run/venv/local/lib/python3.6/site-packages/redis/client.py", line 3159, in _execute
return command(*args, **kwargs)
File "/opt/python/run/venv/local/lib/python3.6/site-packages/redis/connection.py", line 700, in read_response
response = self._parser.read_response()
File "/opt/python/run/venv/local/lib/python3.6/site-packages/redis/connection.py", line 318, in read_response
(str(byte), str(response)))
redis.exceptions.InvalidResponse: Protocol Error: , b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*3'
Respons semua-nol adalah yang paling umum, meskipun saya baru saja melihat ProtocolError: 1, b'575932362]'
berlalu.
Saya tidak mengabaikan kemungkinan bahwa ini juga bisa menjadi kesalahan di Redis dan tidak ada hubungannya dengan Seledri sekalipun. Agak sulit untuk mengatakannya.
Ini menggunakan Seledri 4.3.0, Kombu 4.6.6, dan Redis 3.3.11
Saya mulai sering mendapatkan kesalahan ini setelah menerapkan panggilan async. Aplikasi labu memanggil seledri. Ini berfungsi beberapa kali dan kemudian yang lain saya mendapatkan hasil x00:
web_1 | Traceback (most recent call last):
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/app.py", line 2463, in __call__
web_1 | return self.wsgi_app(environ, start_response)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/app.py", line 2449, in wsgi_app
web_1 | response = self.handle_exception(e)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/app.py", line 1866, in handle_exception
web_1 | reraise(exc_type, exc_value, tb)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
web_1 | raise value
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
web_1 | response = self.full_dispatch_request()
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
web_1 | rv = self.handle_user_exception(e)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
web_1 | reraise(exc_type, exc_value, tb)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
web_1 | raise value
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
web_1 | rv = self.dispatch_request()
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
web_1 | return self.view_functions[rule.endpoint](**req.view_args)
web_1 | File "/usr/src/app/web.py", line 81, in balances
web_1 | result = group(balance.s(name) for name in factories.LAZY_STRATEGY_MAP.keys())().get()
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/celery/result.py", line 703, in get
web_1 | on_interval=on_interval,
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/celery/result.py", line 822, in join_native
web_1 | on_message, on_interval):
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/celery/backends/asynchronous.py", line 151, in iter_native
web_1 | for _ in self._wait_for_pending(result, no_ack=no_ack, **kwargs):
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/celery/backends/asynchronous.py", line 268, in _wait_for_pending
web_1 | on_interval=on_interval):
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/celery/backends/asynchronous.py", line 55, in drain_events_until
web_1 | yield self.wait_for(p, wait, timeout=interval)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/celery/backends/asynchronous.py", line 64, in wait_for
web_1 | wait(timeout=timeout)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/celery/backends/redis.py", line 161, in drain_events
web_1 | message = self._pubsub.get_message(timeout=timeout)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/redis/client.py", line 3565, in get_message
web_1 | response = self.parse_response(block=False, timeout=timeout)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/redis/client.py", line 3453, in parse_response
web_1 | response = self._execute(conn, conn.read_response)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/redis/client.py", line 3427, in _execute
web_1 | return command(*args, **kwargs)
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/redis/connection.py", line 734, in read_response
web_1 | response = self._parser.read_response()
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/redis/connection.py", line 324, in read_response
web_1 | (str(byte), str(response)))
web_1 | redis.exceptions.InvalidResponse: Protocol Error: , b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*3'
Lebih banyak kesalahan aneh:
web_1 | redis.exceptions.InvalidResponse: Protocol Error: s, b'ubscribe'
Dan:
web_1 | File "/root/.local/share/virtualenvs/app-lp47FrbD/lib/python3.7/site-packages/redis/connection.py", line 350, in read_response
web_1 | response = self._buffer.read(length)
web_1 | AttributeError: 'NoneType' object has no attribute 'read'
Python 3.7, Seledri 4.4.1, Redis 3.4.1.
adakah dari Anda yang bisa mencoba tambalan ini https://github.com/celery/celery/pull/5145?
adakah dari kalian yang bisa mencoba patch #5145 ini?
Saya tidak keberatan mencobanya, tetapi saya perhatikan ada banyak pertentangan tentang pendekatan di tambalan itu, build dengan tambalan itu gagal, dan sudah ada di sana selama 17 bulan. Sepertinya ide itu telah ditinggalkan.
cobalah dulu dan jangan 'keberatan meninjau PR dan menyiapkan tes yang gagal untuk itu.
FWIW, dikonfirmasi hari ini bahwa ini masih menjadi masalah dengan Seledri 4.4.2, Kombu 4.6.8, Redis 3.4.1.
Mempertimbangkan berapa lama masalah ini, apakah ada petunjuk tentang apa penyebabnya? Saya tidak berpikir proyek saya telah melihatnya [banyak] baru-baru ini, tetapi bagaimanapun, setidaknya beberapa proyek terus melihat bug ini terjadi.
@jheld Komentar dari https://github.com/celery/celery/issues/4363#issuecomment -411708951 sesuai dengan apa yang saya lihat terakhir kali saya menyodoknya - yaitu hasil konsumen menginisialisasi PubSub yang akhirnya dibagikan di seluruh utas dan bahwa PubSubs tidak aman untuk utas. Solusi saya mengabaikan hasil dan menyimpan/menonton hasil secara independen dari aplikasi Django saya.
Terima kasih atas umpan balik semua orang. Hanya untuk memperjelas beberapa hal:
ResultConsumer
adalah komponen Redis Backend yang secara asinkron mengambil hasilnyaResultConsumer
menginisialisasi instancePubSub
- Instance
ResultConsumer
dapat dibuat baik pada pekerja (alur kerja Kanvas) atau saat Tugas diantrekan dan hasilnya tidak diabaikan- instance
PubSub
tidak dapat digunakan secara bersamaan dari beberapa utas- sejauh menyangkut Pekerja, perubahan ini harus mencakup kasus memulai garpu baru
Saya tidak mengetahui apakah operasi yang sesuai dapat dilakukan pada startup Django, mungkin callback ini dapat membantu; memanggil
ResultConsumer.on_after_fork
kemudian akan membuat instance baru dan masalah kemungkinan besar tidak akan terjadi.
Sebelumnya dalam masalah ini, seseorang menyebutkan ini mulai terjadi setelah mereka memutakhirkan Django:
dan memperbarui Django 1.11 (tambahan. 13 ke .14))
Kami baru saja memutakhirkan dari 1,11 ke 2.2, dan kami mulai melihatnya. Saya tidak dapat membayangkan mengapa, tetapi saya pikir saya akan mengulangi hal di atas.
Saya baru saja memeriksa ini https://github.com/andymccurdy/redis-py/issues/612#issuecomment -515019364 tetapi tidak sepenuhnya yakin