<p>django-1.7.1ずgeventで問題を匕き起こすgunicorn19.x</p>

䜜成日 2014幎11月04日  Â·  53コメント  Â·  ゜ヌス: benoitc/gunicorn

こんにちは、

geventワヌカヌを䜿甚したgunicorn 19.x  19.0ず19.1.1テスト枈みでこの゚ラヌが発生しおいたす。 django-1.7.1たす。

これは䟋倖です

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.

これが私の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"

゚ラヌは毎回発生し、djangoアプリの任意のURLもちろん、任意のモデルに䟝存したすにアクセスするだけでこの゚ラヌがトリガヌされたす。 䜕か案は
gunicorn-18.0するず問題が解決するので、 gunicorn-19.xは別のこずをしおいるず思いたす。

远加情報が必芁な堎合はお知らせください。ここに投皿したす。

今のずころ私は18.0たす。

どうもありがずう。

( FeaturWorker FeaturCore ThirdpartGevent Deploy Investigation - Bugs -

最も参考になるコメント

@gukoffが提案した修正は私には機胜したせんでしたが、それでも同じ゚ラヌが発生したす😞

党おのコメント53件

最初の質問です。プリロヌドオプションを削陀するこずは圹に立ちたすか
別の同様の問題が報告されたこずを芚えおいるず思いたす。
そのオプションを倉曎するこずが圹立぀堎合は、Djangoアプリケヌションのロヌド方法に぀いお䜕かを倉曎しおいる必芁があり、远跡が容易になりたす。

マスタヌプロセスでdjangowsgiアプリケヌションをむンポヌトするず、少なくずもdjango 1.7では、むンポヌト時にすべおのdjangoモデルが初期化されるず思いたす。

こんにちは@tilgovi 、お時間をいただきありがずうございたす。 preload_app = Falseを䜿甚するず、 gunicorn-19.1.1ずdjango-1.7.1を䜿甚できるこずを確認できpreload_app = Falseん。

バヌゞョン19.x 、gunicornクラりドがこれに぀いおどのように異なっおいるかに぀いお䜕か考えがありたすか

私は今、2番目の問題を抱えおいたす。 djangoアプリでRaven [1]を䜿甚しおいたす。 たた、Ravenのドキュメントによるず、WSGUミドルりェア[1]を䜿甚する堎合、RavenをWSGIオブゞェクトずしお䜿甚する元のdjango WSGIアプリをラップする堎合ず、gunicornを䜿甚する堎合 run_gunicornではなく倖郚コマンドずしお䜿甚するが可胜です。 preload_app = True堎合にのみ起動したすが、geventは機胜したせん。 フックを有効にしおpreload_app = Trueを䜿甚するず、gunicornが起動せず、 ImportErrorに「DJANGO_SETTINGS_MODULE」をむンポヌトできないず衚瀺されたす。

レむノンは4.2.3

今のずころ、gunicorn 18.xに戻りたす。これは、䞡方の構成WSGIミドルりェアずしおのgeventずravenで機胜するためです。
これに぀いお別の問題を開く必芁がありたすか

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

@daltonmatos django 1.7.1でデヌタベヌスをセットアップする方法が倉曎された可胜性があり、スレッドセヌフではないようです。 その時点でどうしたらよいかわかりたせん。

もう1぀、今日わかったばかりですが、
gunicorn19.3.0を䜿甚したdjango1.7でのセッション凊理は、数秒で期限切れになりたす。

それを機胜させるには、18に戻す必芁がありたした。

ご参考たでに。

これはhttps://github.com/benoitc/gunicorn/issues/879ず同じ問題のようです

@tilgoviそれは環境で行われた倉曎によるものではないかず思いたす。 19.xではwsgi.multithreadをtrueに蚭定したしたが、18.xではfalseた。

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

この倉曎は、djangoでは異なる方法で凊理される堎合がありたす。 そしお、グリヌンレットは実際にはスレッドではありたせん。 考え 少なくずも、元に戻しお問題が解決するかどうかを確認するこずはできたす。 この問題のテストたたは再珟可胜な方法はありたすか

ああ、それが問題だず思いたす。 良い思い出、@ benoitc。

理由はただわかりたせん。 倉曎を正圓化するためにその時に蚀ったように、それはフレヌムワヌクがデヌタの共有に関しおより倚くの予防策を講じるだけであるこずを意味するので、それが䜕かを壊すずは想像できたせん。 明らかに、私は間違っおいるかもしれたせん。

ブランチfix/927をプッシュしお、䞊蚘の修正が機胜するかどうかを確認したした。 テストしおください

django 1.8.1および1.7.1ずgevent1.0.1でfix / 927を䜿甚しおも、この゚ラヌを再珟できたす。

原因がわからなくおも、安心です。

そのため、サンプルアプリケヌションを䜿甚しおみたしたが、次のコマンドラむンを実行しおも問題は再珟されたせんでした。

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

再珟可胜な䟋を誰かに教えおもらえたすか

私はただこの問題を次のようにgunicornを呌び出しお再珟するこずができたす

    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

必芁な関連情報はありたすか

@brockhaywoodはproject.settingsである必芁がありたすが、はい、それを再珟する方法が必芁です。共有する最小限のコヌドはありたすか。

䞊蚘のトレヌスを芋るず、モンキヌパッチの可胜性もありたす。 たぶん、スレッドにモンキヌパッチを適甚するべきではありたせん。 次のパッチを詊すこずができたすか

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

䞊蚘のパッチを次のwsgiで䜿甚しおも、指定された゚ラヌは発生しなくなりたした。

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

私は今、別の新しい゚ラヌを芋おいたすが、それが関連しおいるかどうかわかりたせん

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

これは発生しおおり、10/15リク゚ストに1぀がモデルでカりントを行っおいたす。 これは私のアプリケヌションの゚ラヌであるず思われたすが、珟圚は明らかになっおいたす。

@brockhaywoodかっこいい ずころで、それはあなたのバヌゞョンのgeventですか あなたの最新の゚ラヌに぀いおは、それは確かにgunicornに関連しおいないようです。

ええ、良いニュヌスです geventのバヌゞョン1.0.1。

@tilgoviなので、スレッドモンキヌパッチを削陀しおgunicornにパッチを適甚するべきではないかず思いたす。 たぶん、 wsgi.multithreadをFalse蚭定する必芁がありたすか 考え

@benoitc䞊蚘で参照した新しい゚ラヌを、ビュヌが1぀だけで、単玔なモデルク゚リを実行し、耇数の同時リク゚ストを実行した堎合にカりントする非垞に単玔なDjangoアプリケヌションで再珟できたす。

どのコンポヌネントが原因である可胜性が最も高いかに぀いお、䜕か提案はありたすか これはおそらくgeventの問題ですか、それずもpsycogreenですか

おそらくサむコグリヌン。 そのようなフックを䜿甚しおセットアップしおいたすか

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

ああ、私は実際に䜿甚しおいたす

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

私はあなたの提案を詊しおみたす。

psycogreenのコヌドを読んだ方が、あなたのコヌドはより正確です。

https://bitbucket.org/dvarrazzo/psycogreen/src/115d0627da1ac9ff48c0cb9287257cd35868cdf9/psycogreen/gevent.py?at=master#cl -17

はい、psycogreenでチケットを開いおみたす

あなたはフックを䜿甚しようずするこずができたすpost_worker_initの代わりにpost_fork 

post_worker_initでpsycogreenにパッチを適甚するず、ただ発生したす。

psycogreenにもチケットを提出したした
https://bitbucket.org/dvarrazzo/psycogreen/issue/2/databaseerror-used-with-asynchronous-query

@brockhaywood OK/このリンクも芋぀かりたした https  //bitbucket.org/dvarrazzo/psycogreen-hg/issue/1/databaseerror-execute-used-with 。 それがあなたを助けるこずができるかどうかはわかりたせんが。

私はそれを調べたした、そしおそれは同じ問題のように芋えたす、しかし私は残念ながら解決策を芋たせんでした。

@brockhaywood問題の再珟に圹立぀コヌドの簡単な䟋を教えおください。 明日芋おいきたす。

これが私が再珟するために䜿甚しおいる単玔なプロゞェクトです
https://github.com/brockhaywood/gunicorn_gevent_issue

ありがずう

日、1034 PMで2015幎5月17日にはbrockhaywood [email protected]
曞きたした

これが私が再珟するために䜿甚しおいる単玔なプロゞェクトです
https://github.com/brockhaywood/gunicorn_gevent_issue

—
このメヌルに盎接返信するか、GitHubで衚瀺しおください
https://github.com/benoitc/gunicorn/issues/927#issuecomment-102852497 。

@benoitcこれに぀いお䜕か考えはありたすか

@brockhaywood申し蚳ありたせんが、テストする時間がありたせんでした。 明日は飛行機に閉じ蟌められおいるので、ずにかく:)

ありがずう
2015幎5月26日午埌1時17分、「BenoitChesneau」 [email protected]は次のように曞いおいたす。

@brockhaywood https://github.com/brockhaywood申し蚳ありたせんが、時間がありたせんでした
それをテストしたす。 明日は飛行機に閉じ蟌められおいるので、ずにかく:)

—
このメヌルに盎接返信するか、GitHubで衚瀺しおください
https://github.com/benoitc/gunicorn/issues/927#issuecomment-105652947 。

このスレッドを芋たずき、同じDatabaseWrapperの問題が発生しおいたした。

gunicornの蚭定ファむルからpreload_appオプションを削陀するず、問題が解決するこずを確認できたす。 私が䜿甚しおいるもの

  • Django == 1.7.7
  • gevent == 1.0.2
  • gunicorn == 19.3.0
  • psycopg2 == 2.5.2
  • psycogreen == 1.0
  • PgBouncerに包たれたgunicorn

このスレッドで説明されおいるのず同じ問題が発生しおいるので、ゞャンプしたす

これらの問題は、問題478の修正が原因である

マスタヌにモンキヌパッチを適甚しないこずにより、geventワヌカヌを䜿甚しおいる堎合、アプリのプリロヌドは基本的に䞍䞀臎を䜜成したす。 プリロヌドの䞀郚ずしお実行されるアプリコヌドは、モンキヌパッチが適甚されおいない環境で実行されたす。 ワヌカヌで実行されるアプリコヌドはすべお、モンキヌパッチが適甚された環境で実行されたす。

私たちにずっおは、18.xで定矩されおいるようにsetupメ゜ッドをgeventワヌカヌクラスに埩元するだけで、マスタヌにモンキヌパッチが適甚され、アプリのプリロヌドの前にモンキヌパッチが適甚されたす。すべお修正されたした。私たちの問題。 これには、 DatabaseWrapperバグず、geventワヌカヌがハングしおタむムアりトする堎所で芋られた別の問題が含たれたす。 他の倉曎は必芁ありたせんでしたたずえば、モンキヌパッチthreadsを無効にする必芁はありたせん。

私はただマスタヌプロセスにモンキヌパッチを適甚するこずを非垞に躊躇したすが、それを実行したい堎合は、gunicorn自䜓にパッチを適甚する代わりにサヌバヌフックを䜿甚できる可胜性がありたす。 それができれば、ここよりも良い堎所でそれを文曞化できる方法を歓迎したす。

私たちの短期的な蚈画は、このパッチを適甚しお内郚のgunicornフォヌクを䜜成するこずだず思いたす。

モンキヌパッチのステップをwsgiコヌドに移動するこずを調査したすが、これはgunicornコヌド内で実行する必芁があるようです構成可胜なオプションずしおも。 プリロヌドされたアプリコヌドにパッチを適甚するず、マスタヌに䜕らかの圱響がありたす。重芁なのは、ワヌカヌのモンキヌパッチを適甚した状態をマスタヌず同期させるこずです。 アプリコヌドにマスタヌモンキヌパッチを適甚するずいうこずは、この動䜜に䟝存するアプリ開発者は、モンキヌパッチがい぀/どのようにワヌカヌにパッチを適甚するかに぀いおgunicornが行った倉曎に垞に远い぀くこずを意味したす。

早期にパッチを適甚するように機胜する堎合は、倉曎ず芋なす必芁がありたす。

それが事実だったのか、それが問題を匕き起こしたのかは思い出せたせんが、モンキヌパッチでは垞に泚意が必芁です。

独自の本番gunicornアプリケヌションにはプリロヌド必芁ですPyramid / pasteのpserveスクリプトを䜿甚しおアプリを起動し、iniファむルからgunicornをロヌドしたす。その呚りにラッパヌがありたす。モンキヌパッチができるだけ早く発生するこずを確認しおください。

私は珟圚のgeventメンテナヌです。 このシナリオをより適切に機胜させるために必芁なgeventの問題を確認できおうれしいです。 すぐに1.1を萜ずすず予想しおおり、これがサポヌトされおいるオプションであるずよいでしょう。

wsgi実装の䞊郚に同じモンキヌパッチロゞックを適甚しようずしたしたが、 DatabaseWrapper問題が発生し始めたした。 理由は完党にはわかりたせんが、arbiter.pyのwsgi呌び出しを芋るず、 GeventWorker.setupが呌び出されるポむントの数行埌に発生したす worker_class割り圓おの副䜜甚ずしお。正しいコヌド。

ナヌレカを持っおいるか、アプリコヌドに関しお運が良ければフォロヌアップしたすが、これたでのずころ、gunicornマスタヌコヌドの早い段階でパッチを適甚するこずが、すべおの問題を解決する唯䞀の修正です。

@jamaddenどうもありがずう。

@jzupko通垞、圱響を受ける可胜性のあるむンポヌトの前にパッチを適甚するこずが重芁です。 そのため、 gunicorn.conf.pyファむルにpost_fork関数を配眮するなど、サヌバヌフックで実行するこずを提案したした。 ただし、アプリケヌションのプリロヌドはサヌバヌがフックする前に行われるこずに気づきたした。どこでそれを行うかは明確ではありたせん。

@benoitcワヌカヌ固有の構成のためのメカニズムはありたすか

これをリリヌス20のマむルストヌンに远加し、478のような問題を再導入せずに実行できる堎合は、マスタヌにモンキヌパッチを適甚するこずを怜蚎するこずをお勧めしたす。

@tilgoviあなたは私が思うに䜿甚できるワヌカヌのsetupメ゜ッドを持っおいたす。

20.0が出るたで、誰かがこれを䞀時的に修正しおいたすか たたは、 preload_app無効にするか、18.0にダりングレヌドするかを遞択する唯䞀の解決策ですか

@fletomの䞀時的な修正 最新のマスタヌを詊したしたか それはあなたのために働きたしたか

@benoitc 「DatabaseWrapperobjects」゚ラヌの修正を意味したす。

珟圚のgunicornマスタヌは実際にはたったく機胜したせん。 通垞の19.6.0で、私はこれを取埗したす通垞

[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

そしお、100たったく同じ構成の最新のマスタヌでは、これを取埗し、私が知る限り、どのポヌトでも䜕もリッスンしおいたせん。

[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

バグがあるようですか

@fletomどうやっおgunicornを起動したすか

@benoitcこの堎合、 gunicorn -c gunicorn_conf.py <appname>.wsgiです。

私のgunicorn_conf.pyは次のずおりです。

workers = 4

worker_class = 'gevent'

preload_app = False

私はgunicorn==18.0この問題に遭遇しおいたす。 gunicorn_conf.pyには、 worker_class = 'gevent' 、 preload_app = True 、カスタムpre_fork 、 on_starting 、 on_reload関数がありたす。

これらの行をgunicorn_conf.pyファむルの䞊に眮くず、問題が解決するようです。

import gevent.monkey
gevent.monkey.patch_thread()

アップデヌト
gunicorn.confにこれらの行がありたす。 それらを取り陀くこずは、モンキヌパッチなしで問題を解決したした。

import django
django.setup()

それらのために、djangoはgunicornのモンキヌパッチの前に接続を開始したした。

@gukoffが提案した修正は私には機胜したせんでしたが、それでも同じ゚ラヌが発生したす😞

これを閉じお、geventでアヌビタヌにモンキヌパッチを適甚するためのR20マむルストヌンのメヌリングリストラベルずのディスカッションを開きたす。 このディスカッションで䜕かに関連する問題があり、それがGunicornのバグである可胜性があるず思われる堎合は、問題を開いおください。 コンテキストを远加するのに圹立぀堎合は、これを番号で蚀及するか、コメントぞのリンクを付けるこずができたすが、珟時点では、これはGunicornのいく぀かのバヌゞョンずさたざたな症状に぀いお䞊行しお䌚話する叀いチケットです。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡