ããã«ã¡ã¯ã
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
ãŸãã
ã©ããããããšãã
æåã®è³ªåã§ããããªããŒããªãã·ã§ã³ãåé€ããããšã¯åœ¹ã«ç«ã¡ãŸããïŒ
å¥ã®åæ§ã®åé¡ãå ±åãããããšãèŠããŠãããšæããŸãã
ãã®ãªãã·ã§ã³ãå€æŽããããšã圹ç«ã€å Žåã¯ã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ã®ã³ãŒããèªãã æ¹ããããªãã®ã³ãŒãã¯ããæ£ç¢ºã§ãã
ã¯ãã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
ãªãã·ã§ã³ãåé€ãããšãåé¡ã解決ããããšã確èªã§ããŸãã ç§ã䜿çšããŠãããã®ïŒ
ïŒãã®ã¹ã¬ããã§èª¬æãããŠããã®ãšåãåé¡ãçºçããŠããã®ã§ããžã£ã³ãããŸãïŒ
ãããã®åé¡ã¯ãåé¡ïŒ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ã®ããã€ãã®ããŒãžã§ã³ãšããŸããŸãªçç¶ã«ã€ããŠäžŠè¡ããŠäŒè©±ããå€ããã±ããã§ãã
æãåèã«ãªãã³ã¡ã³ã
@gukoffãææ¡ããä¿®æ£ã¯ç§ã«ã¯æ©èœããŸããã§ããããããã§ãåããšã©ãŒãçºçããŸãð