<p>django-1.7.1 ๋ฐ gevent์— ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค๋Š” gunicorn 19.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 ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋กœ๋“œ๋˜๋Š” ๋ฐฉ์‹์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๊ณ  ์ถ”์ ํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ ์–ด๋„ django 1.7์—์„œ๋Š” ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋ชจ๋“  django ๋ชจ๋ธ์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋งˆ์Šคํ„ฐ ํ”„๋กœ์„ธ์Šค์—์„œ django wsgi ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ _์ƒ๊ฐ_ํ•ฉ๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @tilgovi , ์‹œ๊ฐ„ ๋‚ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. preload_app = False ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ gunicorn-19.1.1 ๋ฐ django-1.7.1 ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

19.x ๋ฒ„์ „์—์„œ ์ด์— ๋Œ€ํ•ด gunicorn ํด๋ผ์šฐ๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์ด์ œ ๋‘ ๋ฒˆ์งธ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด 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์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์„ค์ •๋˜๋Š” ๋ฐฉ์‹์€ ์•„๋งˆ๋„ ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ์‹œ์ ์—์„œ ๋ฌด์—‡์„ ํ•ด์•ผ ํ• ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋˜ ํ•˜๋‚˜ ์˜ค๋Š˜ ์•Œ๊ฒŒ ๋œ ์‚ฌ์‹ค,
gunicorn 19.3.0์ด ํฌํ•จ๋œ django 1.7์˜ ์„ธ์…˜ ์ฒ˜๋ฆฌ๊ฐ€ ๋ช‡ ์ดˆ ์•ˆ์— ๋งŒ๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

์ž‘๋™ํ•˜๋ ค๋ฉด 18๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ

์ด๊ฒƒ์€ ํ์‡„๋˜์—ˆ์ง€๋งŒ ์ˆ˜์ •๋˜์ง€ ์•Š์€ https://github.com/benoitc/gunicorn/issues/879 ์™€ ๋™์ผํ•œ ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ gunicorn 19.x๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. Django์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ gevent ์ž‘์—…์ž์—๊ฒŒ๋งŒ ํ•ด๋‹น๋ฉ๋‹ˆ๊นŒ? ๋‹ค๋ฅธ ์ž‘์—…์ž ์œ ํ˜•์— ๋Œ€ํ•ด์„œ๋Š” ํ…Œ์ŠคํŠธํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

@tilgovi ํ™˜๊ฒฝ์—์„œ ์ˆ˜ํ–‰๋œ ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•œ ๊ฒƒ์ด wsgi.multithread ๋ฅผ true ๋กœ ์„ค์ •ํ–ˆ์œผ๋ฉฐ 18.x์—์„œ๋Š” false ์˜€์Šต๋‹ˆ๋‹ค.

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

์ด ๋ณ€๊ฒฝ์€ django์—์„œ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  greenlet์€ ์‹ค์ œ๋กœ ์Šค๋ ˆ๋“œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ƒ๊ฐ? ์ ์–ด๋„ ๋˜๋Œ๋ฆฌ๊ณ  ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜๋Š” ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ๋˜๋Š” ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์•„, ๊ทธ๊ฒŒ ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™์•„์š”. ์ข‹์€ ๊ธฐ์–ต, @benoitc.

์•„์ง๊นŒ์ง€๋Š” ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ์„ ์ •๋‹นํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋‹น์‹œ์— ๋งํ–ˆ๋“ฏ์ด ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋ฐ์ดํ„ฐ ๊ณต์œ ์— ๋Œ€ํ•ด ๋” ๋งŽ์€ ์˜ˆ๋ฐฉ ์กฐ์น˜๋ฅผ ์ทจํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ฌด ๊ฒƒ๋„ ์ค‘๋‹จํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ, ๋‚ด๊ฐ€ ํ‹€๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์ˆ˜์ • ์‚ฌํ•ญ์ด ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„๊ธฐ fix/927 ๋ฅผ ํ‘ธ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ํ•ด์ฃผ์„ธ์š”!

๋‚˜๋Š” ์—ฌ์ „ํžˆ django 1.8.1(๋ฐ 1.7.1) ๋ฐ gevent 1.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 ๋ฉ‹์ง€๋‹ค! btw ahat ๋‹น์‹ ์˜ gevent ๋ฒ„์ „์ž…๋‹ˆ๊นŒ? ์ตœ์‹  ์˜ค๋ฅ˜์˜ ๊ฒฝ์šฐ ์‹ค์ œ๋กœ gunicorn๊ณผ ๊ด€๋ จ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ข‹์€ ์†Œ์‹์ž…๋‹ˆ๋‹ค! gevent ๋ฒ„์ „ 1.0.1์—์„œ.

@tilgovi ๊ทธ๋ž˜์„œ ์Šค๋ ˆ๋“œ ์›์ˆญ์ด ํŒจ์น˜๋ฅผ ์ œ๊ฑฐํ•˜๋Š” gunicorn์„ ํŒจ์น˜ํ•ด์„œ๋Š” ์•ˆ๋˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. wsgi.multithread ๋„ False ํ•ด์•ผ ํ• ๊นŒ์š”? ์ƒ๊ฐ?

@benoitc ๋ณด๊ธฐ๊ฐ€ ํ•˜๋‚˜๋งŒ ์žˆ๊ณ  ์—ฌ๋Ÿฌ ๋™์‹œ ์š”์ฒญ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐ„๋‹จํ•œ ๋ชจ๋ธ ์ฟผ๋ฆฌ ๋ฐ ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋งค์šฐ ๊ฐ„๋‹จํ•œ 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

์ข‹์•„, ์‹ธ์ด์ฝ”๊ทธ๋ฆฐ์œผ๋กœ ํ‹ฐ์ผ“์„ ์—ด์–ด๋ณผ๊ฒŒ

๋‹น์‹ ์€ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค post_worker_init ๋Œ€์‹  post_fork ?

post_worker_init์—์„œ 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

๊ฐ์‚ฌ ํ•ด์š”!

2015๋…„ 5์›” 17์ผ ์ผ์š”์ผ ์˜คํ›„ 10:34 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๋ถ„์— "Benoit Chesneau" [email protected]์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

@brockhaywood https://github.com/brockhaywood ์‹œ๊ฐ„์ด ์—†์–ด์„œ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค
๊ทธ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. ๋‚ด์ผ ๋น„ํ–‰๊ธฐ์— ๋ฌถ์—ฌ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์–ด์จŒ๋“  ๊ฐˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค :)

โ€”
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ฑฐ๋‚˜ GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/benoitc/gunicorn/issues/927#issuecomment -105652947.

์ด ์Šค๋ ˆ๋“œ๋ฅผ ๋ณด์•˜์„ ๋•Œ ๋™์ผํ•œ DatabaseWrapper ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด gunicorn ๊ตฌ์„ฑ ํŒŒ์ผ์—์„œ preload_app ์˜ต์…˜์„ ์ œ๊ฑฐํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋œ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‚ฌ์šฉํ•˜๊ณ ์žˆ๋‹ค :

  • ์žฅ๊ณ ==1.7.7
  • gevent==1.0.2
  • gunicorn==19.3.0
  • ์‚ฌ์ด์ฝ”ํ”„2==2.5.2
  • ์‚ฌ์ด์ฝ”๊ทธ๋ฆฐ==1.0
  • PgBouncer์— ์˜ํ•ด ๊ฐ์‹ธ์ธ gunicorn

(์ด ์Šค๋ ˆ๋“œ์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ๋ณด๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋›ฐ์–ด๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.)

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋Š” ๋ฌธ์ œ #478 (์›์ˆญ์ด ํŒจ์น˜๋ฅผ ๋งˆ์Šคํ„ฐํ•˜์ง€ ์•Š์Œ)์— ๋Œ€ํ•œ ์ˆ˜์ • ์œผ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์›์ˆญ์ด๊ฐ€ ๋งˆ์Šคํ„ฐ๋ฅผ ํŒจ์น˜ํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ gevent ์ž‘์—…์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์•ฑ ์‚ฌ์ „ ๋กœ๋“œ๋Š” ๊ทผ๋ณธ์ ์œผ๋กœ ๋ถˆ์ผ์น˜๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์ „ ๋กœ๋“œ์˜ ์ผ๋ถ€๋กœ ์‹คํ–‰๋˜๋Š” ๋ชจ๋“  ์•ฑ ์ฝ”๋“œ๋Š” ์›์ˆญ์ด ํŒจ์น˜๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์€ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ž‘์—…์ž์—์„œ ์‹คํ–‰๋˜๋Š” ๋ชจ๋“  ์•ฑ ์ฝ”๋“œ๋Š” ์›์ˆญ์ด ํŒจ์น˜ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ ๊ฒฝ์šฐ setup ๋ฉ”์†Œ๋“œ๋ฅผ gevent ์ž‘์—…์ž ํด๋ž˜์Šค๋กœ ๋ณต์›ํ•˜๊ธฐ setup ํ•˜๋ฉด 18.x์— ์ •์˜๋œ ๋Œ€๋กœ ๋งˆ์Šคํ„ฐ๊ฐ€ ์›์ˆญ์ด ํŒจ์น˜๋˜๊ณ  ์•ฑ ์‚ฌ์ „ ๋กœ๋“œ ์ด์ „์— ์›์ˆญ์ด ํŒจ์น˜๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ๋ฌธ์ œ. ์—ฌ๊ธฐ์—๋Š” 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 "DatabaseWrapper objects" ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์ˆ˜์ •์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ 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 ๋“ฑ๊ธ‰