Gunicorn: OSError: [Errno 9] 잘λͺ»λœ 파일 μ„€λͺ…μž

에 λ§Œλ“  2018λ…„ 09μ›” 10일  Β·  19μ½”λ©˜νŠΈ  Β·  좜처: benoitc/gunicorn

raspbian μ΄λ―Έμ§€μ—μ„œ 이 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

[2018-09-10 20:40:11 +0800] [21421] [CRITICAL] μž‘μ—…μž μ‹œκ°„ 초과(pid:21699)
[2018-09-10 20:40:11 +0800] [21699] [ERROR] μ†ŒμΌ“ 였λ₯˜ 처리 μš”μ²­μž…λ‹ˆλ‹€.
역좔적(κ°€μž₯ 졜근 호좜 λ§ˆμ§€λ§‰):
파일 "/usr/lib/python3/dist-packages/gunicorn/workers/async.py", 62ν–‰, ν•Έλ“€
Six.reraise(*sys.exc_info())
파일 "/usr/lib/python3/dist-packages/gunicorn/six.py", 625ν–‰, μž¬μƒμŠΉ
κ°€μΉ˜λ₯Ό 높이닀
파일 "/usr/lib/python3/dist-packages/gunicorn/workers/async.py", 35ν–‰, ν•Έλ“€
listener_name = listener.getsockname()
OSError: [Errno 9] 잘λͺ»λœ 파일 μ„€λͺ…μž

Feedback Requested Investigation

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

  1. gunicorn 및 uvicorn μ„€μ •μœΌλ‘œ 이 둜그 였λ₯˜λ₯Ό μž¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 였λ₯˜ λ©”μ‹œμ§€λŠ” 이전 버전 0.11.3 μ•„λ‹ˆλΌ uvicorn==0.11.4 λ°œμƒν•˜κΈ° μ‹œμž‘ν•©λ‹ˆλ‹€(OSx 및 Linux μ»¨ν…Œμ΄λ„ˆ λͺ¨λ‘μ—μ„œ). μ΄λŠ” 보고된 버전이 항상 0.11.4 보닀 큰 uvicorn의 μœ„ λ³΄κ³ μ„œμ™€ μΌμΉ˜ν•©λ‹ˆλ‹€. λ§ˆμ§€λ§‰μ— 증거
  2. 이 였λ₯˜μ— λŒ€ν•œ μ±…μž„μ΄ 컀밋 ν•˜λ‚˜ . λ¬Έμ œλŠ” 방금 μ–ΈκΈ‰ν•œ μ»€λ°‹μ˜ 이 λͺ‡ 쀄 에 μžˆμŠ΅λ‹ˆλ‹€. 컀밋은 두 μ½”λ“œ λΈ”λ‘μ˜ μˆœμ„œλ§Œ λ³€κ²½ν•©λ‹ˆλ‹€. κ·Έ μˆœμ„œ 변경을 되돌리면 uvicorn 의 ν…ŒμŠ€νŠΈ μŠ€μœ„νŠΈλ₯Ό 계속 ν†΅κ³Όν•˜λ©΄μ„œ 둜그 였λ₯˜κ°€ μ‚¬λΌμ§‘λ‹ˆλ‹€.
  3. λ™μΌν•œ 둜그 였λ₯˜λŠ” λ‹€μŒ 쀑 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜λŠ” 경우 λ°œμƒν•©λ‹ˆλ‹€. μœ„μ— 보고된 λŒ€λ‘œ gunicorn+uvicorn μŠ€νƒ 맨 μœ„μ— starlette 및 fastapi λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. - 12.X λŒ€μ‹  μ΅œμ‹  uvicorn 버전 0.11.4 ; - ν•œ λͺ… μ΄μƒμ˜ uvicorn μž‘μ—…μžμ™€ ν•¨κ»˜ gunicorn μ‹€ν–‰

증거 . osx의 μƒˆ ν΄λ”μ—μ„œ μ²¨λΆ€λœ 슀크립트 test.sh (osxμ—μ„œ ν…ŒμŠ€νŠΈλ¨)λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€. Linux μ»¨ν…Œμ΄λ„ˆμ—μ„œ ν…ŒμŠ€νŠΈν•˜λ €λ©΄ μŠ€ν¬λ¦½νŠΈμ™€ Dockerfile을 λͺ¨λ‘ μ €μž₯ν•œ λ‹€μŒ Dockerfile의 헀더λ₯Ό μ½μœΌμ‹­μ‹œμ˜€. 슀크립트 λ‘œκ·Έλ„ μ²¨λΆ€ν•©λ‹ˆλ‹€.

@benoitc , uvicorn 의 이 컀밋에 λŒ€ν•΄ μ–΄λ–»κ²Œ μƒκ°ν•˜μ„Έμš”? 버그가 λ°œμƒν•˜λŠ” 것 κ°™λ‚˜μš”? λ¬Έμ œλŠ” gunicorn 와 uvicorn μ‚¬μ΄μ˜ μΈν„°νŽ˜μ΄μŠ€μ— μžˆλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. uvicorn μ—μ„œ μœ„μ—μ„œ μ–ΈκΈ‰ν•œ μ»€λ°‹μ—μ„œ λ³€κ²½λœ 2개의 μ½”λ“œ 블둝 μˆœμ„œμ— λŒ€ν•΄ μ–ΈκΈ‰ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? μ΄λ ‡κ²Œ ν•˜λ©΄ λ‹€λ₯Έ κ²½μš°μ—λ„ 이런 일이 λ°œμƒν•˜λŠ” 이유λ₯Ό μ°ΎλŠ” 데 도움이 될 수 μžˆμŠ΅λ‹ˆλ‹€. μ§€κΈˆκΉŒμ§€ 이것은 aiohttp , gevent , Flask-SocketIO sanic . 편의λ₯Ό μœ„ν•΄ 슀크립트 λ‘œκ·Έλ„ μ²¨λΆ€ν•©λ‹ˆλ‹€.

log_test.log

파일 _test.sh_

#!/bin/bash
python3 -m venv venv
source venv/bin/activate
pip install gunicorn==20.0.04 uvicorn==0.11.4
# create simple uvicorn app
printf "async def app(scope, receive, send):\n    await send()\n" > example.py
# spin up gunicorn with 1 uvicorn worker, and then send TERM signal to gunicorn
gunicorn example:app -w 1 -k uvicorn.workers.UvicornWorker &
sleep 5 && pkill -f gunicorn
sleep 1
# you will see 1 log entry like this one:
# [XX] [YY] [INFO] Error while closing socket [Errno 9] Bad file descriptor

printf "\n\n[INFO] if you instead bump down uvicorn's version from 11.4 to 11.3 [Errno 9] goes away:\n\n"
pip install uvicorn==0.11.3
gunicorn example:app -w 1 -k uvicorn.workers.UvicornWorker &
sleep 5 && pkill -f gunicorn

파일 _λ„μ»€νŒŒμΌ_

# run with:
# docker run -it $(docker build -q .)
FROM python:3.8
COPY test.sh .
RUN chmod +x /test.sh
CMD /test.sh

λͺ¨λ“  19 λŒ“κΈ€

@leond08 ν‹°μΌ“ κ°μ‚¬ν•©λ‹ˆλ‹€!

μ–΄λ–»κ²Œ λ°œμƒν•˜λŠ”μ§€ μ΄ν•΄ν•˜κΈ° μœ„ν•΄ 쑰금 더 정보λ₯Ό μ œκ³΅ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

  • ν…ŒμŠ€νŠΈ 쀑인 Gunicorn 버전
  • μ–΄λ–€ μž‘μ—…μžλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆκΉŒ?
  • μ–Έμ œ 이런 일이 λ°œμƒν•©λ‹ˆκΉŒ?

λ‚˜λŠ” gunicorn3 μ΅œμ‹  버전을 μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€
λ‚˜λŠ” 이것을 μœ„ν•΄ eventletκ³Ό geventλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
λ‚΄ ν”ŒλΌμŠ€ν¬ μ‘μš© ν”„λ‘œκ·Έλž¨μ„ μ‹€ν–‰ μ€‘μž…λ‹ˆλ‹€ - Flask-SocketIO

μ‚¬μš©μžκ°€ λ²„νŠΌμ„ ν΄λ¦­ν•œ ν›„ λ°±κ·ΈλΌμš΄λ“œ μž‘μ—…μ„ μ‹œμž‘ν•©λ‹ˆλ‹€.
λ‚΄ λ°±κ·ΈλΌμš΄λ“œ μž‘μ—… κΈ°λŠ₯은 이벀트λ₯Ό μˆ˜μ‹ ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
"μ™„λ£Œ" λ²„νŠΌμ„ ν΄λ¦­ν•œ ν›„ λ°±κ·ΈλΌμš΄λ“œ μž‘μ—…μ΄ μ€‘μ§€λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.
그런 λ‹€μŒ λͺ¨λ“  μ‚¬μš©μžμ—κ²Œ 방좜 λ©”μ‹œμ§€λ₯Ό λ³΄λƒ…λ‹ˆλ‹€.

aiohttp + gunicornκ³Ό λ™μΌν•œ λ¬Έμ œκ°€ μžˆμ—ˆλŠ”λ° ctrl + cλ₯Ό ν•  λ•Œλ§ˆλ‹€ λ™μΌν•œ λ©”μ‹œμ§€λ₯Ό κ΄€μ°°ν•˜μ‹­μ‹œμ˜€.

[INFO] μ†ŒμΌ“μ„ λ‹«λŠ” λ™μ•ˆ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. [Errno 9] 잘λͺ»λœ 파일 μ„€λͺ…μž

λ‚˜λŠ” 그것을 μž¬μƒμ‚°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. κ·€ν•˜μ˜ μ‘μš© ν”„λ‘œκ·Έλž¨μ΄ μœ„μ˜ 문제λ₯Ό μΌμœΌν‚€λŠ” 일뢀 fdλ₯Ό λ‹«κ³  μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

μš°λ¦¬λŠ” λ™μΌν•œ 문제λ₯Ό κ²ͺκ³  μžˆμŠ΅λ‹ˆλ‹€. μœ μΌν•œ λ¬Έμ œλŠ” 도컀 λ–Όμ—μ„œ μ‹€ν–‰λ˜λŠ” μ»¨ν…Œμ΄λ„ˆ 8개 쀑 1κ°œμ—μ„œλ§Œ λ°œμƒν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

μš°λ¦¬λŠ” 9개의 μ»¨ν…Œμ΄λ„ˆ 쀑 1κ°œμ—μ„œ λ™μΌν•œ 문제λ₯Ό κ²½ν—˜ν–ˆμŠ΅λ‹ˆλ‹€. docker 및 python3 및 gevent와 κ΄€λ ¨λœ 것 κ°™μŠ΅λ‹ˆλ‹€.

gunicorn 20.0.4 + aiohttp 3.6.2

Gunicorn이 개발 μ„œλ²„λ‘œ μ‹€ν–‰ μ€‘μž…λ‹ˆλ‹€.

gunicorn --reload app:make_app --bind localhost:5000 --worker-class aiohttp.GunicornWebWorker --workers 2 --access-logfile -

거의 λͺ¨λ“  Ctrl+CλŠ” λ‹€μŒμœΌλ‘œ λλ‚©λ‹ˆλ‹€.

^C[2020-05-23 21:49:50 +0200] [38524] [INFO] Handling signal: int
Exception ignored when trying to write to the signal wakeup fd:
Exception ignored when trying to write to the signal wakeup fd:
Traceback (most recent call last):
  File "/usr/lib/python3.8/asyncio/unix_events.py", line 42, in _sighandler_noop
Traceback (most recent call last):
  File "/usr/lib/python3.8/asyncio/unix_events.py", line 42, in _sighandler_noop
    def _sighandler_noop(signum, frame):
    def _sighandler_noop(signum, frame):
OSError: [Errno 9] Bad file descriptor
OSError: [Errno 9] Bad file descriptor
[2020-05-23 21:49:50 +0200] [38526] [INFO] Worker exiting (pid: 38526)
[2020-05-23 21:49:50 +0200] [38528] [INFO] Worker exiting (pid: 38528)
[2020-05-23 21:49:50 +0200] [38524] [INFO] Shutting down: Master

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μš”μ²­μ„ μ²˜λ¦¬ν–ˆλŠ”μ§€ μ—¬λΆ€λŠ” μ€‘μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

Sanic 20.3.0 μ‚¬μš©:

^C[2020-05-26 13:24:55 +0200] [27706] [INFO] Handling signal: int
[2020-05-26 13:24:55 +0200] [27769] [INFO] Stopping server: 27769, connections: 0
[2020-05-26 13:24:55 +0200] [27769] [INFO] Error while closing socket [Errno 9] Bad file descriptor
[2020-05-26 13:24:55 +0200] [27769] [INFO] Worker exiting (pid: 27769)
[2020-05-26 13:24:55 +0200] [27771] [INFO] Stopping server: 27771, connections: 0
[2020-05-26 13:24:55 +0200] [27771] [INFO] Error while closing socket [Errno 9] Bad file descriptor
[2020-05-26 13:24:55 +0200] [27771] [INFO] Worker exiting (pid: 27771)
[2020-05-26 13:24:55 +0200] [27706] [INFO] Shutting down: Master

λͺ¨λ“  Ctrl+Cμ—μ„œ Gunicorn 20.0.4 + Uvicorn 0.11.5 μž‘μ—…μž ν΄λž˜μŠ€μ™€ 동일

INFO:     [12621] [gunicorn.error] Handling signal: int
INFO:     [12635] [gunicorn.error] Error while closing socket [Errno 9] Bad file descriptor
INFO:     [12634] [gunicorn.error] Error while closing socket [Errno 9] Bad file descriptor
INFO:     [12635] [gunicorn.error] Worker exiting (pid: 12635)
INFO:     [12634] [gunicorn.error] Worker exiting (pid: 12634)
INFO:     [12621] [gunicorn.error] Shutting down: Master

적용 μ˜ˆκ°€ μžˆμŠ΅λ‹ˆκΉŒ? λ˜ν•œ μ–΄λ–€ λ²„μ „μ˜ Python에 λŒ€ν•΄ μ΄μ•ΌκΈ°ν•˜κ³  μžˆμŠ΅λ‹ˆκΉŒ?

Ubuntu 20.04, virtualenvμ—μ„œ μ‹œμŠ€ν…œ 제곡 Python 3.8.2

예제 μ• ν”Œλ¦¬μΌ€μ΄μ…˜: https://github.com/zgoda/newsloop-server/tree/d603a1c10c9e8be3d998f62ccc55dd73f4677115(aiohttp 포함 ) λ˜λŠ” https://github.com/zgoda/newsloop-server/tree/b2a8a7f09fa98 λ‚΄ 이전 μ˜κ²¬μ—μ„œ μ •ν™•ν•œ gunicorn 호좜.

iohttp와 Sanic μ‚¬μ΄μ˜ 좜λ ₯ 차이둜 인해 μž‘μ—…μžμ™€ κ΄€λ ¨λœ λ¬Έμ œκ°€ μžˆλ‹€λŠ” μ˜μ‹¬μ΄ λ“­λ‹ˆλ‹€.

λ™μΌν•œ 문제, Python 3.8.0
μ œμ •μ‹  19.12.2
κ·€λ‹ˆμ½˜ 20.0.4

νŽΈμ§‘: 이것은 λ‚΄ Macμ—μ„œ 둜컬둜 μ‹€ν–‰ν•  λ•Œ λ°œμƒν•˜μ§€λ§Œ Linux 도컀 λ‚΄μ—μ„œ μ‹€ν–‰ν•  λ•ŒλŠ” λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 도움이 될 수 μžˆμŠ΅λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš”,
이 문제 https://github.com/benoitc/gunicorn/issues/2064 도 같은 μ΄μœ κ°€ μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.
λ¬Έμ œμ™€ 거의 λ™μΌν•œ 였λ₯˜κ°€ μžˆμ§€λ§Œ gunicorn - 19.9.0을 μ‚¬μš©ν•©λ‹ˆλ‹€.

저도 이것을 κ²½ν—˜ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. FastAPI + Python 3.8.5λ₯Ό μ‚¬μš©ν•˜λŠ” μ΅œμ‹  Gunicorn 및 uvicorn μž‘μ—…μž

uvicorn μ‚¬μš©μ„ μ€‘λ‹¨ν•˜μžλ§ˆμž(즉, λ‚΄ gunicorn κ΅¬μ„±μ—μ„œ 이 쀄을 제거):

worker_class = "uvicorn.workers.UvicornWorker"

였λ₯˜κ°€ μ‚¬λΌμ§‘λ‹ˆλ‹€.

μœ„μ—μ„œ μ„€λͺ…ν•œ κ²ƒμ²˜λŸΌ Ctrl+C둜 Gunicorn을 μ€‘μ§€ν•˜κ±°λ‚˜ PID에 Graceful kill μ‹ ν˜Έλ₯Ό 보낼 λ•Œ λ°œμƒν•©λ‹ˆλ‹€.

[2020-09-12 11:56:37 +1000] [100390] [INFO] Starting gunicorn 20.0.4
[2020-09-12 11:56:37 +1000] [100390] [INFO] Listening at: http://0.0.0.0:6000 (100390)
[2020-09-12 11:56:37 +1000] [100390] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2020-09-12 11:56:37 +1000] [100392] [INFO] Booting worker with pid: 100392
[2020-09-12 11:56:38 +1000] [100392] [INFO] Started server process [100392]
[2020-09-12 11:56:38 +1000] [100392] [INFO] Waiting for application startup.
[2020-09-12 11:56:38 +1000] [100392] [INFO] Application startup complete.
[2020-09-12 11:56:48 +1000] [100390] [INFO] Handling signal: term
[2020-09-12 11:56:48 +1000] [100392] [INFO] Shutting down
[2020-09-12 11:56:48 +1000] [100392] [INFO] Error while closing socket [Errno 9] Bad file descriptor
[2020-09-12 11:56:48 +1000] [100392] [INFO] Waiting for application shutdown.
[2020-09-12 11:56:48 +1000] [100392] [INFO] Application shutdown complete.
[2020-09-12 11:56:48 +1000] [100392] [INFO] Finished server process [100392]
[2020-09-12 11:56:48 +1000] [100392] [INFO] Worker exiting (pid: 100392)
[2020-09-12 11:56:48 +1000] [100390] [INFO] Shutting down: Master

문제의 μ •ν™•ν•œ λ³΅μ œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

[fots<strong i="6">@workstation</strong> testing]$ python3.8 -V
Python 3.8.5
[fots<strong i="7">@workstation</strong> testing]$ python3.8 -m venv ~/.virtualenv/testing
[fots<strong i="8">@workstation</strong> testing]$ source ~/.virtualenv/testing/bin/activate
(testing) [fots<strong i="9">@workstation</strong> testing]$ pip install fastapi gunicorn uvicorn
Collecting fastapi
  Using cached fastapi-0.61.1-py3-none-any.whl (48 kB)
Collecting gunicorn
  Using cached gunicorn-20.0.4-py2.py3-none-any.whl (77 kB)
Collecting uvicorn
  Using cached uvicorn-0.11.8-py3-none-any.whl (43 kB)
Collecting pydantic<2.0.0,>=1.0.0
  Using cached pydantic-1.6.1-cp38-cp38-manylinux2014_x86_64.whl (11.5 MB)
Collecting starlette==0.13.6
  Using cached starlette-0.13.6-py3-none-any.whl (59 kB)
Requirement already satisfied: setuptools>=3.0 in /home/fots/.virtualenv/testing/lib/python3.8/site-packages (from gunicorn) (47.1.0)
Collecting h11<0.10,>=0.8
  Using cached h11-0.9.0-py2.py3-none-any.whl (53 kB)
Collecting websockets==8.*
  Using cached websockets-8.1-cp38-cp38-manylinux2010_x86_64.whl (78 kB)
Collecting httptools==0.1.*; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy"
  Using cached httptools-0.1.1-cp38-cp38-manylinux1_x86_64.whl (227 kB)
Collecting uvloop>=0.14.0; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy"
  Using cached uvloop-0.14.0-cp38-cp38-manylinux2010_x86_64.whl (4.7 MB)
Collecting click==7.*
  Using cached click-7.1.2-py2.py3-none-any.whl (82 kB)
Installing collected packages: pydantic, starlette, fastapi, gunicorn, h11, websockets, httptools, uvloop, click, uvicorn
Successfully installed click-7.1.2 fastapi-0.61.1 gunicorn-20.0.4 h11-0.9.0 httptools-0.1.1 pydantic-1.6.1 starlette-0.13.6 uvicorn-0.11.8 uvloop-0.14.0 websockets-8.1
WARNING: You are using pip version 20.1.1; however, version 20.2.3 is available.
You should consider upgrading via the '/home/fots/.virtualenv/testing/bin/python3.8 -m pip install --upgrade pip' command.
(testing) [fots<strong i="10">@workstation</strong> testing]$ ls -l
total 4
-rw-rw-r-- 1 fots fots 117 Sep 12 12:13 main.py
(testing) [fots<strong i="11">@workstation</strong> testing]$ cat main.py
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}
(testing) [fots<strong i="12">@workstation</strong> testing]$ gunicorn -k uvicorn.workers.UvicornWorker main:app
[2020-09-12 12:19:05 +1000] [105788] [INFO] Starting gunicorn 20.0.4
[2020-09-12 12:19:05 +1000] [105788] [INFO] Listening at: http://127.0.0.1:8000 (105788)
[2020-09-12 12:19:05 +1000] [105788] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2020-09-12 12:19:05 +1000] [105790] [INFO] Booting worker with pid: 105790
[2020-09-12 12:19:05 +1000] [105790] [INFO] Started server process [105790]
[2020-09-12 12:19:05 +1000] [105790] [INFO] Waiting for application startup.
[2020-09-12 12:19:05 +1000] [105790] [INFO] Application startup complete.
^C[2020-09-12 12:19:06 +1000] [105788] [INFO] Handling signal: int
[2020-09-12 12:19:06 +1000] [105790] [INFO] Shutting down
[2020-09-12 12:19:06 +1000] [105790] [INFO] Error while closing socket [Errno 9] Bad file descriptor
[2020-09-12 12:19:06 +1000] [105790] [INFO] Waiting for application shutdown.
[2020-09-12 12:19:06 +1000] [105790] [INFO] Application shutdown complete.
[2020-09-12 12:19:06 +1000] [105790] [INFO] Finished server process [105790]
[2020-09-12 12:19:06 +1000] [105790] [INFO] Worker exiting (pid: 105790)
[2020-09-12 12:19:07 +1000] [105788] [INFO] Shutting down: Master

λ‹€μŒμ€ pip freeze 좜λ ₯μž…λ‹ˆλ‹€.

click==7.1.2
fastapi==0.61.1
gunicorn==20.0.4
h11==0.9.0
httptools==0.1.1
pydantic==1.6.1
starlette==0.13.6
uvicorn==0.11.8
uvloop==0.14.0
websockets==8.1

μ΅œμ‹  μˆ˜μ • 사항을 λ°›μ•˜λŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ GitHub(λ§ˆμŠ€ν„° 브랜치)μ—μ„œ uvicornκ³Ό gunicorn을 μ„€μΉ˜ν•˜λ €κ³  μ‹œλ„ν–ˆμ§€λ§Œ λ¬Έμ œκ°€ μ§€μ†λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

도움이 λ˜μ—ˆκΈ°λ₯Ό λ°”λžλ‹ˆλ‹€
ν¬ν‹°μŠ€

  1. gunicorn 및 uvicorn μ„€μ •μœΌλ‘œ 이 둜그 였λ₯˜λ₯Ό μž¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 였λ₯˜ λ©”μ‹œμ§€λŠ” 이전 버전 0.11.3 μ•„λ‹ˆλΌ uvicorn==0.11.4 λ°œμƒν•˜κΈ° μ‹œμž‘ν•©λ‹ˆλ‹€(OSx 및 Linux μ»¨ν…Œμ΄λ„ˆ λͺ¨λ‘μ—μ„œ). μ΄λŠ” 보고된 버전이 항상 0.11.4 보닀 큰 uvicorn의 μœ„ λ³΄κ³ μ„œμ™€ μΌμΉ˜ν•©λ‹ˆλ‹€. λ§ˆμ§€λ§‰μ— 증거
  2. 이 였λ₯˜μ— λŒ€ν•œ μ±…μž„μ΄ 컀밋 ν•˜λ‚˜ . λ¬Έμ œλŠ” 방금 μ–ΈκΈ‰ν•œ μ»€λ°‹μ˜ 이 λͺ‡ 쀄 에 μžˆμŠ΅λ‹ˆλ‹€. 컀밋은 두 μ½”λ“œ λΈ”λ‘μ˜ μˆœμ„œλ§Œ λ³€κ²½ν•©λ‹ˆλ‹€. κ·Έ μˆœμ„œ 변경을 되돌리면 uvicorn 의 ν…ŒμŠ€νŠΈ μŠ€μœ„νŠΈλ₯Ό 계속 ν†΅κ³Όν•˜λ©΄μ„œ 둜그 였λ₯˜κ°€ μ‚¬λΌμ§‘λ‹ˆλ‹€.
  3. λ™μΌν•œ 둜그 였λ₯˜λŠ” λ‹€μŒ 쀑 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜λŠ” 경우 λ°œμƒν•©λ‹ˆλ‹€. μœ„μ— 보고된 λŒ€λ‘œ gunicorn+uvicorn μŠ€νƒ 맨 μœ„μ— starlette 및 fastapi λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. - 12.X λŒ€μ‹  μ΅œμ‹  uvicorn 버전 0.11.4 ; - ν•œ λͺ… μ΄μƒμ˜ uvicorn μž‘μ—…μžμ™€ ν•¨κ»˜ gunicorn μ‹€ν–‰

증거 . osx의 μƒˆ ν΄λ”μ—μ„œ μ²¨λΆ€λœ 슀크립트 test.sh (osxμ—μ„œ ν…ŒμŠ€νŠΈλ¨)λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€. Linux μ»¨ν…Œμ΄λ„ˆμ—μ„œ ν…ŒμŠ€νŠΈν•˜λ €λ©΄ μŠ€ν¬λ¦½νŠΈμ™€ Dockerfile을 λͺ¨λ‘ μ €μž₯ν•œ λ‹€μŒ Dockerfile의 헀더λ₯Ό μ½μœΌμ‹­μ‹œμ˜€. 슀크립트 λ‘œκ·Έλ„ μ²¨λΆ€ν•©λ‹ˆλ‹€.

@benoitc , uvicorn 의 이 컀밋에 λŒ€ν•΄ μ–΄λ–»κ²Œ μƒκ°ν•˜μ„Έμš”? 버그가 λ°œμƒν•˜λŠ” 것 κ°™λ‚˜μš”? λ¬Έμ œλŠ” gunicorn 와 uvicorn μ‚¬μ΄μ˜ μΈν„°νŽ˜μ΄μŠ€μ— μžˆλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. uvicorn μ—μ„œ μœ„μ—μ„œ μ–ΈκΈ‰ν•œ μ»€λ°‹μ—μ„œ λ³€κ²½λœ 2개의 μ½”λ“œ 블둝 μˆœμ„œμ— λŒ€ν•΄ μ–ΈκΈ‰ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? μ΄λ ‡κ²Œ ν•˜λ©΄ λ‹€λ₯Έ κ²½μš°μ—λ„ 이런 일이 λ°œμƒν•˜λŠ” 이유λ₯Ό μ°ΎλŠ” 데 도움이 될 수 μžˆμŠ΅λ‹ˆλ‹€. μ§€κΈˆκΉŒμ§€ 이것은 aiohttp , gevent , Flask-SocketIO sanic . 편의λ₯Ό μœ„ν•΄ 슀크립트 λ‘œκ·Έλ„ μ²¨λΆ€ν•©λ‹ˆλ‹€.

log_test.log

파일 _test.sh_

#!/bin/bash
python3 -m venv venv
source venv/bin/activate
pip install gunicorn==20.0.04 uvicorn==0.11.4
# create simple uvicorn app
printf "async def app(scope, receive, send):\n    await send()\n" > example.py
# spin up gunicorn with 1 uvicorn worker, and then send TERM signal to gunicorn
gunicorn example:app -w 1 -k uvicorn.workers.UvicornWorker &
sleep 5 && pkill -f gunicorn
sleep 1
# you will see 1 log entry like this one:
# [XX] [YY] [INFO] Error while closing socket [Errno 9] Bad file descriptor

printf "\n\n[INFO] if you instead bump down uvicorn's version from 11.4 to 11.3 [Errno 9] goes away:\n\n"
pip install uvicorn==0.11.3
gunicorn example:app -w 1 -k uvicorn.workers.UvicornWorker &
sleep 5 && pkill -f gunicorn

파일 _λ„μ»€νŒŒμΌ_

# run with:
# docker run -it $(docker build -q .)
FROM python:3.8
COPY test.sh .
RUN chmod +x /test.sh
CMD /test.sh

λ‚˜λŠ” λ˜‘κ°™μ€ λ¬Έμ œκ°€μžˆμ—ˆμŠ΅λ‹ˆλ‹€. μ—¬κΈ° λ‚΄ κ²½μš°κ°€ μžˆμŠ΅λ‹ˆλ‹€.

μš”μ•½ : gunicorn을 μ‚¬μš©ν•˜μ—¬ Django dwebsocket에 λŒ€ν•œ ν…ŒμŠ€νŠΈ μ‘μš© ν”„λ‘œκ·Έλž¨μ„ μ„€μ •ν•˜λ €κ³  ν•©λ‹ˆλ‹€. websocket_clientλ₯Ό μ‚¬μš©ν•˜μ—¬ κ²°κ³Όλ₯Ό ν…ŒμŠ€νŠΈν•˜λ €κ³  ν•  λ•Œ websocket을 닫은 ν›„ 이 였λ₯˜κ°€ 맀번 λ°œμƒν•©λ‹ˆλ‹€.

ν™˜κ²½ :
도컀 이미지 : python:3.7
파이썬 버전: python3.7.6
gunicorn : 버전 = 20.0.4, μž‘μ—… = gevent
Django 버전 : Django==2.2
dwebsocket 버전 : 0.5.12

μ•”ν˜Έ:

보기.py

from dwebsocket import accept_websocket

<strong i="16">@accept_websocket</strong>
def my_ws(request):
    if request.is_websocket():
        ws = request.websocket
        while True:
            msg = ws.wait(timeout=15)
            if msg is None:
                print('get None message')
                break
            else:
                msg = b'echo :' + msg
                ws.send(msg)
                print('send ws seccess')
        print('websocket close')

urls.py

from websocketInfo.views import  my_ws
from django.conf.urls import url

urlpatterns = [
    url(r'my_ws/$', my_ws, name='my_ws')
]

μ›Ή μ†ŒμΌ“_ν΄λΌμ΄μ–ΈνŠΈ

from websocket import create_connection
ws = create_connection("ws://127.0.0.1:8080/my_ws/")
print("Sending 'Hello, World'...")
ws.send("Hello, World")
print("Receiving...")
result = ws.recv()
print(result)
ws.close()
print('ws close')

gunicorn μ„œλ²„λ₯Ό μ‹€ν–‰ν•˜λŠ” commad

gunicorn MyWebsocket.wsgi -b 0.0.0.0:8000 -w 3 -k gevent

였λ₯˜ 좜λ ₯

send ws seccess
get None message
websocket close
[2021-01-13 02:43:56 +0000] [101] [ERROR] Socket error processing request.
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base_async.py", line 65, in handle
    util.reraise(*sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 625, in reraise
    raise value
  File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base_async.py", line 55, in handle
    self.handle_request(listener_name, req, client, addr)
  File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/ggevent.py", line 143, in handle_request
    super().handle_request(listener_name, req, sock, addr)
  File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base_async.py", line 128, in handle_request
    util.reraise(*sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 625, in reraise
    raise value
  File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base_async.py", line 114, in handle_request
    resp.write(item)
  File "/usr/local/lib/python3.7/site-packages/gunicorn/http/wsgi.py", line 326, in write
    self.send_headers()
  File "/usr/local/lib/python3.7/site-packages/gunicorn/http/wsgi.py", line 322, in send_headers
    util.write(self.sock, util.to_bytestring(header_str, "latin-1"))
  File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 286, in write
    sock.sendall(data)
  File "/usr/local/lib/python3.7/site-packages/gevent/_socket3.py", line 523, in sendall
    return _socketcommon._sendall(self, data_memory, flags)
  File "/usr/local/lib/python3.7/site-packages/gevent/_socketcommon.py", line 367, in _sendall
    chunk_size = max(socket.getsockopt(SOL_SOCKET, SO_SNDBUF), 1024 * 1024)
  File "/usr/local/lib/python3.7/site-packages/gevent/_socket3.py", line 156, in __getattr__
    return getattr(self._sock, name)
  File "/usr/local/lib/python3.7/site-packages/gevent/_socket3.py", line 66, in _dummy
    raise OSError(EBADF, 'Bad file descriptor')
OSError: [Errno 9] Bad file descriptor

@ChrisXiaoShu κ²Œμ‹œν•œ μŠ€νƒ 좔적은 이 νŠΉμ • μ†ŒμΌ“ κ°œμ²΄κ°€ Python μˆ˜μ€€μ—μ„œ λͺ…μ‹œμ μœΌλ‘œ λ‹« _dummy λ₯Ό μ‚¬μš©ν•˜μ—¬ 운영 μ²΄μ œμ™€ λ™μΌν•œ μ˜ˆμ™Έλ₯Ό 생성함). μ΄λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μŠ€νƒμ˜ 일뢀가 gunicorn이 μ²˜λ¦¬ν•  수 μžˆλ„λ‘ 응닡을 λ°˜ν™˜ν•˜κΈ° 전에 μ†ŒμΌ“μ„ λ‹«κ³  μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€. 였λ₯˜κ°€ λ°œμƒν•˜λŠ” μ‹œμ μ—μ„œ gunicorn은 아직 HTTP 응닡 헀더λ₯Ό 보내지 μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

이 였λ₯˜κ°€ 아무 κ²ƒλ„ν•˜μ§€ μ•Šκ³  λ°œμƒν•œλ‹€λŠ” 차이점과 ν•¨κ»˜ λ‚΄ κ²½μš°μ—λŠ” λ™μΌν•œ λ¬Έμ œμž…λ‹ˆλ‹€. λ•Œλ‘œλŠ” 5λΆ„ ν›„, λ•Œλ‘œλŠ” 2μ‹œκ°„ ν›„...

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰