<p>gunicorn 19.x menyebabkan masalah dengan Django-1.7.1 dan gevent</p>

Dibuat pada 4 Nov 2014  ·  53Komentar  ·  Sumber: benoitc/gunicorn

Halo,

Saya melihat kesalahan ini dengan gunicorn 19.x (diuji dengan 19.0 dan 19.1.1 ) menggunakan gevent worker. Saya menggunakan django-1.7.1 .

ini pengecualian:

Traceback:
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  87.                 response = middleware_method(request)
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/auth/middleware.py" in process_request
  34.         if user and hasattr(user, 'get_session_auth_hash'):
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/utils/functional.py" in inner
  224.             self._setup()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/utils/functional.py" in _setup
  357.         self._wrapped = self._setupfunc()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/auth/middleware.py" in <lambda>
  23.         request.user = SimpleLazyObject(lambda: get_user(request))
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/auth/middleware.py" in get_user
  11.         request._cached_user = auth.get_user(request)
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/auth/__init__.py" in get_user
  151.         user_id = request.session[SESSION_KEY]
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/sessions/backends/base.py" in __getitem__
  49.         return self._session[key]
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/sessions/backends/base.py" in _get_session
  175.                 self._session_cache = self.load()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/sessions/backends/db.py" in load
  21.                 expire_date__gt=timezone.now()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/manager.py" in manager_method
  92.                 return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py" in get
  351.         num = len(clone)
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py" in __len__
  122.         self._fetch_all()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py" in _fetch_all
  966.             self._result_cache = list(self.iterator())
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py" in iterator
  265.         for row in compiler.results_iter():
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in results_iter
  700.         for rows in self.execute_sql(MULTI):
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
  784.         cursor = self.connection.cursor()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/backends/__init__.py" in cursor
  163.         self.validate_thread_sharing()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/backends/__init__.py" in validate_thread_sharing
  515.                 % (self.alias, self._thread_ident, thread.get_ident()))

Exception Type: DatabaseError at /
Exception Value: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 140049505195808 and this is thread id 61130224.

Ini gunicorn.conf.py :

##
# Gunicorn config at 
# Managed by Chef - Local Changes will be Nuked from Orbit (just to be sure)
##

# What ports/sockets to listen on, and what options for them.
bind = "127.0.0.1:9300"

# The maximum number of pending connections
backlog = 2048

# What the timeout for killing busy workers is, in seconds
timeout = 300

# How long to wait for requests on a Keep-Alive connection, in seconds
keepalive = 2

# The maxium number of requests a worker will process before restarting
max_requests = 1024

# Whether the app should be pre-loaded
preload_app = True

# How many worker processes
workers = 16

# Type of worker to use
worker_class = "gevent"

# The granularity of error log outputs.
loglevel = "error"

Kesalahan terjadi setiap kali, hanya mengakses URL apa pun dari aplikasi Django (yang bergantung pada model apa pun, tentu saja) memicu kesalahan ini. Ada ide?
Karena mengubah ke gunicorn-18.0 menyelesaikan masalah, saya berasumsi bahwa gunicorn-19.x melakukan sesuatu yang berbeda.

Jika Anda memerlukan informasi tambahan, beri tahu saya dan saya akan mempostingnya di sini.

Untuk saat ini saya menggunakan 18.0 .

Terima kasih banyak.

( FeaturWorker FeaturCore ThirdpartGevent Deploy Investigation - Bugs -

Komentar yang paling membantu

@gukoff perbaikan yang diusulkan tidak berhasil untuk saya, saya masih mendapatkan kesalahan yang sama

Semua 53 komentar

Hanya pertanyaan pertama: apakah menghapus opsi pramuat membantu?
Saya pikir saya ingat masalah serupa lainnya yang dilaporkan.
Jika mengubah opsi itu membantu, maka kita pasti telah mengubah sesuatu tentang bagaimana aplikasi Django dimuat dan akan lebih mudah bagi kita untuk melacaknya.

Saya _berpikir_ kita mengimpor aplikasi django wsgi dalam proses master, yang setidaknya pada Django 1.7, menginisialisasi semua model django pada impor.

Halo @tilgovi , terima kasih atas waktunya. Saya tidak dapat mengonfirmasi bahwa menggunakan preload_app = False Saya dapat menggunakan gunicorn-19.1.1 dan django-1.7.1 .

Apakah Anda tahu apa yang gunicorn cloud lakukan secara berbeda tentang ini di versi 19.x ?

Saya sekarang punya masalah kedua. Saya menggunakan Raven[1] di aplikasi Django saya. Dan menurut dokumen Raven, saat menggunakan middleware WSGU[1] dimungkinkan untuk menggunakan Raven sebagai objek WSGI (membungkus aplikasi WSGI Django asli), dan saat menggunakan gunicorn (sebagai perintah eksternal, bukan run_gunicorn perintah django) kita harus menambahkan pengait ke gunicorn [2]. Saat kait ini diaktifkan, gunicorn hanya melakukan booting jika preload_app = True , tetapi kemudian gevent tidak berfungsi. Ketika saya menggunakan preload_app = True dengan pengait diaktifkan, gunicorn bahkan tidak bisa boot, memberi saya dan ImportError mengatakan itu tidak dapat mengimpor "DJAGO_SETTINGS_MODULE" saya.

Gagak adalah 4.2.3

Untuk saat ini saya akan kembali ke gunicorn 18.x , karena berfungsi dengan kedua konfigurasi (gevent dan raven sebagai middleware WSGI)
Haruskah saya membuka Masalah lain tentang ini?

[1] http://raven.readthedocs.org/en/latest/config/django.html#wsgi -middleware
[2] http://raven.readthedocs.org/en/latest/config/Django.html#gunicorn

@daltonmatos cara database diatur di Django 1.7.1 mungkin telah berubah tampaknya bukan threadsafe. Saya tidak yakin apa yang harus dilakukan pada saat itu.

Satu hal lagi, baru tahu hari ini,
penanganan sesi di Django 1.7 dengan gunicorn 19.3.0 berakhir dalam hitungan detik.

Harus beralih kembali ke 18 untuk membuatnya bekerja.

FYI.

Ini tampaknya menjadi masalah yang sama dengan https://github.com/benoitc/gunicorn/issues/879 , yang ditutup tetapi tidak diperbaiki. Itu membuat gunicorn 19.x. tidak dapat digunakan dengan Django. Mungkin hanya untuk pekerja gevent? Saya belum menguji untuk jenis pekerja lain.

@tilgovi saya ingin tahu apakah itu bukan karena perubahan yang dilakukan di lingkungan. di 19.x kita set wsgi.multithread ke true mana false di 18.x :

https://github.com/benoitc/gunicorn/blob/master/gunicorn/workers/ggevent.py#L99

Perubahan ini dapat ditangani secara berbeda di Django. Dan greenlet sebenarnya bukan utas. Pikiran? Setidaknya mungkin kita bisa mencoba mengembalikannya dan memeriksa apakah itu menyelesaikan masalah. Apakah kita memiliki tes atau cara yang dapat direproduksi untuk masalah ini?

Oh, saya yakin itu masalahnya. Ingatan yang bagus, @benoitc.

Aku masih belum tahu kenapa. Seperti yang saya katakan pada saat itu untuk membenarkan perubahan tersebut, saya tidak dapat membayangkan bahwa itu akan merusak apa pun karena itu berarti bahwa kerangka kerja hanya akan mengambil lebih banyak tindakan pencegahan tentang berbagi data. Jelas, saya mungkin salah.

Saya mendorong cabang fix/927 untuk memeriksa apakah perbaikan di atas berfungsi. Silakan uji!

Saya masih dapat mereproduksi kesalahan ini menggunakan fix/927 dengan Django 1.8.1 (dan 1.7.1) dan gevent 1.0.1

Itu meyakinkan saya, bahkan jika kita masih tidak tahu penyebabnya.

Jadi saya mencoba menggunakan contoh aplikasi dan tidak mereproduksi masalah menjalankan baris perintah berikut:

gunicorn --env DJANGO_SETTINGS_MODULE=testing.settings -k gevent -w3 wsgi:application

Adakah yang bisa memberi saya contoh yang dapat direproduksi?

Saya masih dapat mereproduksi masalah ini dengan menggunakan gunicorn seperti:

    gunicorn --env DJANGO_SETTINGS_MODULE=settings -w 3 --max-requests=1000 -b 0.0.0.0:8000 -k gevent --config ogs/gunicorn.py  --pythonpath ogs wsgi:application

Apakah ada detail relevan yang Anda butuhkan?

@brockhaywood seharusnya project.settings , tapi ya saya harus memiliki cara untuk mereproduksinya, apakah Anda memiliki kode minimal untuk dibagikan.

Melihat jejak di atas, itu juga bisa menjadi penambalan monyet. Mungkin utas tidak boleh ditambal monyet. Bisakah Anda mencoba tambalan berikut?

--- a/gunicorn/workers/ggevent.py
+++ b/gunicorn/workers/ggevent.py
@@ -60,9 +60,9 @@ class GeventWorker(AsyncWorker):

         # if the new version is used make sure to patch subprocess
         if gevent.version_info[0] == 0:
-            monkey.patch_all()
+            monkey.patch_all(thread=False)
         else:
-            monkey.patch_all(subprocess=True)
+            monkey.patch_all(subprocess=True, thread=False)

         # monkey patch sendfile to make it none blocking
         patch_sendfile()

Menggunakan tambalan di atas dengan wsgi berikut tidak lagi menghasilkan kesalahan yang ditentukan:

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")

from gevent import monkey
monkey.patch_all(thread=False)

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

from django.core.cache.backends.memcached import BaseMemcachedCache
BaseMemcachedCache.close = lambda self, **kwargs: None

Saya sekarang melihat kesalahan yang berbeda dan baru tetapi tidak tahu apakah itu terkait:

ProgrammingError: close cannot be used while an asynchronous query is underway

Hal ini terjadi, 1in 10/15 permintaan melakukan hitungan pada model. Saya menduga ini adalah kesalahan dalam aplikasi saya yang sekarang ditemukan.

@brockhaywood keren! btw apa itu gevent versi kamu? Untuk kesalahan terbaru Anda, mati sepertinya tidak terkait dengan gunicorn.

Yah, kabar baik! Pada versi 1.0.1 dari gevent.

@tilgovi jadi saya ingin tahu apakah kita tidak harus menambal gunicorn menghapus tambalan monyet utas. Mungkin kita juga harus mengatur wsgi.multithread ke False ? Pikiran?

@benoitc Saya dapat mereproduksi kesalahan baru yang saya rujuk di atas dengan aplikasi Django yang sangat sederhana yang hanya memiliki satu tampilan dan melakukan kueri dan penghitungan model sederhana jika saya menjalankan beberapa permintaan bersamaan.

Apakah Anda punya saran tentang komponen mana yang paling mungkin menjadi penyebab? Apakah ini kemungkinan masalah gevent atau psycogreen?

Lebih mungkin psycogreen. Apakah Anda menggunakan kait seperti itu untuk mengaturnya?

def def_post_fork(server, worker):
    from psycogreen.gevent import psyco_gevent
    psyco_gevent.make_psycopg_green()
    worker.log.info("Made Psycopg Green")

Oh, saya benar-benar menggunakan

def post_fork(server, worker):    
    from psycogreen.gevent import patch_psycopg
    patch_psycopg()

Saya akan mencoba saran Anda.

Ok, saya akan mencoba membuka tiket dengan psycogreen

dapatkah Anda mencoba menggunakan kait post_worker_init alih-alih post_fork ?

Masih terjadi pada saya ketika menambal psycogreen di post_worker_init.

Saya telah mengirimkan tiket ke psycogreen juga:
https://bitbucket.org/dvarrazzo/psycogreen/issue/2/databaseerror-used-with-asynchronous-query

@brockhaywood OK :/ Juga temukan tautan ini: https://bitbucket.org/dvarrazzo/psycogreen-hg/issue/1/databaseerror-execute-used-with . Saya tidak yakin apakah itu bisa membantu Anda.

Saya memang melihat itu dan sepertinya masalah yang sama tetapi saya tidak melihat resolusi, sayangnya.

@brockhaywood dapatkah Anda membagikan contoh kode sederhana yang dapat membantu saya mereproduksi masalah? Aku akan melihatnya besok.

Di sini proyek sederhana yang saya gunakan untuk mereproduksi:
https://github.com/brockhaywood/gunicorn_gevent_issue

Terima kasih!

Pada hari Minggu, 17 Mei 2015 jam 22:34 brockhaywood [email protected]
menulis:

Di sini proyek sederhana yang saya gunakan untuk mereproduksi:
https://github.com/brockhaywood/gunicorn_gevent_issue


Balas email ini secara langsung atau lihat di GitHub
https://github.com/benoitc/gunicorn/issues/927#issuecomment -102852497.

@benoitc ada pemikiran tentang ini?

@brockhaywood maaf saya tidak punya waktu untuk mengujinya. Karena saya terkunci dalam penerbangan besok, saya akan tetap melakukannya :)

Terima kasih
Pada 26 Mei 2015 13:17, "Benoit Chesneau" [email protected] menulis:

@brockhaywood https://github.com/brockhaywood maaf saya tidak punya waktu
untuk mengujinya. Karena saya terkunci dalam penerbangan besok, saya akan tetap melakukannya :)


Balas email ini secara langsung atau lihat di GitHub
https://github.com/benoitc/gunicorn/issues/927#issuecomment -105652947.

Baru saja mengalami masalah DatabaseWrapper yang sama ketika saya melihat utas ini.

Saya dapat mengonfirmasi bahwa menghapus opsi preload_app dari file konfigurasi gunicorn saya memperbaiki masalah. Saya menggunakan:

  • Django==1.7.7
  • acara == 1.0.2
  • gunicorn == 19.3.0
  • psycopg2==2.5.2
  • psycogreen == 1.0
  • gunicorn dibungkus oleh PgBouncer

(melompat karena kami telah melihat masalah yang sama seperti yang dijelaskan di utas ini)

Sepertinya masalah ini disebabkan oleh perbaikan untuk masalah #478 (jangan monyet menambal master).

Dengan tidak menambal master, pramuat aplikasi pada dasarnya membuat ketidakcocokan jika Anda menggunakan pekerja gevent. Kode aplikasi apa pun yang berjalan sebagai bagian dari pramuat berjalan di lingkungan yang tidak ditambal oleh monyet. Kode aplikasi apa pun yang berjalan di pekerja berjalan di lingkungan yang ditambal monyet.

Bagi kami, cukup pulihkan metode setup ke kelas pekerja gevent seperti yang didefinisikan di 18.x, sehingga master ditambal monyet dan ditambal monyet sebelum pramuat aplikasi, memperbaiki semua masalah kami. Ini termasuk bug DatabaseWrapper , serta masalah lain yang kami lihat di mana pekerja gevent akan hang dan timeout. Tidak ada perubahan lain yang diperlukan (misalnya kita tidak harus menonaktifkan patching monyet threads ).

Saya masih ragu-ragu untuk menambal monyet pada proses master, tetapi jika Anda ingin melakukannya, Anda mungkin dapat menggunakan kait server alih-alih menambal gunicorn itu sendiri. Jika Anda bisa melakukannya, saya akan menyambut baik cara kita dapat mendokumentasikannya di suatu tempat yang lebih baik daripada di sini.

Saya pikir rencana jangka pendek bagi kami adalah membuat garpu gunicorn (internal) dengan tambalan ini diterapkan.

Saya akan menyelidiki memindahkan langkah patch monyet ke dalam kode wsgi kami, tetapi ini masih tampak seperti sesuatu yang harus dilakukan di dalam kode gunicorn (bahkan sebagai opsi yang dapat dikonfigurasi). Menambal dalam kode aplikasi yang dimuat sebelumnya akan memengaruhi master dengan satu atau lain cara, dan intinya adalah untuk menjaga status tambalan monyet dari pekerja tetap sinkron dengan master. Menerapkan tambalan monyet master dalam kode aplikasi berarti bahwa pengembang aplikasi yang bergantung pada perilaku ini akan selalu mengejar perubahan apa pun yang dibuat gunicorn ketika/bagaimana monyet menambal pekerja.

Jika berhasil menambal lebih awal, mungkin itu harus dianggap sebagai perubahan.

Saya tidak ingat apakah itu pernah terjadi dan apakah itu menyebabkan masalah, tetapi selalu rumit dengan penambalan monyet.

Aplikasi gunicorn produksi kami sendiri memerlukan pramuat dan juga memerlukan patch monyet di master (kami menggunakan skrip pserve Pyramid/paste untuk meluncurkan aplikasi dan memuat gunicorn dari file ini; kami memiliki pembungkus di sekitarnya untuk menjadi yakin bahwa penambalan monyet terjadi ASAP).

Saya seorang pengelola gevent saat ini. Saya senang melihat masalah apa pun di gevent yang diperlukan untuk membuat skenario ini berfungsi lebih baik. Kami memperkirakan akan segera turun 1,1 dan akan sangat bagus jika ini adalah opsi yang didukung.

Saya mencoba menerapkan logika patch monyet yang sama di bagian atas implementasi wsgi kami, dan kami mulai melihat masalah DatabaseWrapper . Tidak sepenuhnya yakin mengapa - melihat permintaan wsgi di arbiter.py , itu terjadi beberapa baris setelah titik di mana GeventWorker.setup akan dipanggil (sebagai efek samping dari tugas worker_class . Jika saya membaca kode yang benar.

Saya akan menindaklanjuti jika saya memiliki eureka atau beruntung sehubungan dengan kode aplikasi, tetapi sejauh ini bagi kami, menambal lebih awal dalam kode master gunicorn adalah satu-satunya perbaikan yang menyelesaikan semua masalah kami.

@jamadden terima kasih banyak.

@jzupko biasanya penting bahwa penambalan terjadi sebelum impor apa pun yang mungkin terpengaruh. Itu sebabnya saya menyarankan untuk melakukannya di server hook, seperti dengan meletakkan fungsi post_fork dalam file gunicorn.conf.py . Namun, saya baru menyadari bahwa pra-pemuatan aplikasi terjadi sebelum salah satu server terhubung dan tidak jelas di mana seseorang akan melakukannya.

@benoitc apakah kami memiliki mekanisme untuk konfigurasi khusus pekerja?

Saya menambahkan ini ke tonggak rilis 20 dan menyarankan agar kami mempertimbangkan monkey patching master, mungkin, jika itu dapat dilakukan tanpa menimbulkan kembali masalah seperti #478.

@tilgovi Anda memiliki setup metode pekerja yang dapat digunakan untuk itu saya pikir.

Adakah yang punya perbaikan sementara untuk ini hingga 20.0 keluar? Atau apakah satu-satunya solusi untuk memilih antara menonaktifkan preload_app atau menurunkan versi ke 18.0?

@fletom perbaikan sementara untuk? Apakah Anda mencoba master terbaru? Apakah itu berhasil untuk Anda?

@benoitc Maksud saya perbaikan untuk kesalahan "objek DatabaseWrapper".

Master gunicorn saat ini sebenarnya tidak bekerja sama sekali untuk saya. Pada 19.6.0 reguler saya mendapatkan ini (normal):

[2017-01-05 15:46:32 -0500] [3222] [INFO] Starting gunicorn 19.6.0
[2017-01-05 15:46:32 -0500] [3222] [INFO] Listening at: http://127.0.0.1:8000 (3222)
[2017-01-05 15:46:32 -0500] [3222] [INFO] Using worker: gevent
[2017-01-05 15:46:32 -0500] [3226] [INFO] Booting worker with pid: 3226
[2017-01-05 15:46:32 -0500] [3227] [INFO] Booting worker with pid: 3227
[2017-01-05 15:46:32 -0500] [3228] [INFO] Booting worker with pid: 3228
[2017-01-05 15:46:32 -0500] [3229] [INFO] Booting worker with pid: 3229

Dan pada master terbaru dengan konfigurasi yang sama persis 100% saya mendapatkan ini, dan tidak ada yang mendengarkan pada port apa pun sejauh yang saya tahu:

[2017-01-05 15:47:19 -0500] [3308] [INFO] Starting gunicorn 19.6.0
[2017-01-05 15:47:19 -0500] [3308] [INFO] Listening at:  (3308)
[2017-01-05 15:47:19 -0500] [3308] [INFO] Using worker: gevent
[2017-01-05 15:47:19 -0500] [3312] [INFO] Booting worker with pid: 3312
[2017-01-05 15:47:19 -0500] [3313] [INFO] Booting worker with pid: 3313
[2017-01-05 15:47:19 -0500] [3314] [INFO] Booting worker with pid: 3314
[2017-01-05 15:47:19 -0500] [3315] [INFO] Booting worker with pid: 3315

Sepertinya disadap?

@fletom bagaimana Anda meluncurkan gunicorn?

@benoitc Dalam hal ini, itu gunicorn -c gunicorn_conf.py <appname>.wsgi .

gunicorn_conf.py adalah:

workers = 4

worker_class = 'gevent'

preload_app = False

Saya menemukan masalah ini dengan gunicorn==18.0 . Di gunicorn_conf.py saya memiliki fungsi worker_class = 'gevent' , preload_app = True dan custom pre_fork , on_starting dan on_reload .

Menempatkan baris-baris ini di atas file gunicorn_conf.py tampaknya menyelesaikan masalah bagi saya:

import gevent.monkey
gevent.monkey.patch_thread()

Memperbarui:
Saya memiliki baris-baris ini di gunicorn.conf saya. Menyingkirkan mereka memecahkan masalah tanpa menambal monyet.

import django
django.setup()

Karena mereka, Django memulai koneksi sebelum penambalan monyet gunicorn.

@gukoff perbaikan yang diusulkan tidak berhasil untuk saya, saya masih mendapatkan kesalahan yang sama

Saya akan menutup ini dan membuka diskusi dengan label milis pada tonggak R20 untuk menambal monyet arbiter di gevent. Jika Anda mengalami masalah terkait dengan apa pun dalam diskusi ini dan menurut Anda itu mungkin bug di Gunicorn, silakan buka masalah. Anda dapat menyebutkan yang ini dengan nomor, atau menautkan ke komentar, jika itu membantu menambah konteks, tetapi pada titik ini ini adalah tiket lama dengan percakapan paralel tentang beberapa versi Gunicorn dan gejala yang berbeda.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat