[Gunicorn] Auto - Reload 적용하기

유영석·2023년 11월 20일
0

잡다한 정보

목록 보기
2/15
post-thumbnail

동기

현재 인턴으로 근무 중인 회사에서 Django를 프레임워크로 백엔드 개발을 하고 있습니다. 조금 더 보태자면 Django REST Framework(DRF)를 사용하여 개발 중입니다. 이러한 Python 기반의 Web Application Server(WAS)를 Nginx 같은 Web Server에서 실행시키기 위해서는 Gateway Interfae(GI) 라는 녀석이 필요합니다. 가장 처음으로 등장한 CGI(Common Gateway Interface) 부터 가장 보편적인 WSGI(Web Server Gateway Interface), 그리고 비동기를 효과적으로 지원하기 위해 탄생한 ASGI(Asynchronous Server Gateway Interface) 까지 존재합니다.

현재, 제가 있는 곳에서는 WSGI인 Gunicorn 을 사용합니다. 앞서 언급한 Nginx와 DRF 모두 Docker container 위에서 띄워서 사용하는데, 문제는 소스 코드를 수정하면 컨테이너를 다시 재시작해야 한다는 것입니다. 컨테이너를 다시 재부팅하는 데는 적지 않은 시간이 걸리기 때문에 개발 환경에서 이는 정말 스트레스 받는 일이 아닐 수 없었습니다.

python manage.py runserver

위와 같은 명령어를 써서 Django 자체에서 지원하는 WSGI 를 써서 돌릴 때에는 소스 코드가 변경하면 자동으로 바로 Djagno Application만 재시작 하였습니다. 그런데 Gunicorn을 사용하면 그게 기본적으로 되지 않습니다. 그래서 Document 를 찾아보면 --reload 옵션을 사용하라고 합니다.

첨부: Gunicorn 모델

--reload 옵션에 대한 설명을 보면 worker 를 재시작 해준다고 합니다. 대충 Django Application을 재시작 한다는 느낌인 건... 알겠는데 정확히 뭘까요? Gunicorn의 서버 모델은 pre-fork worker model을 기반으로 하고 있습니다.

중심이 되는 Master 프로세스에서 요청에 따라 여러 Worker 프로세스를 생성하고 관리하는 형태를 뜻합니다. 즉 실질적으로 요청에 대한 응답을 만드는 과정은 모두 이 worker 에서 이루어지도록 하는 것이죠. 전형적인 Master-Slave 관계입니다. 또한 옵션에 따라 이 worker들을 프로세스보다 가벼운 스레드 형태, 뿐만 아니라 다양한 비동기 형태로 사용할 수 있습니다. Gunicorn에서는 각각을 Gthread Worker, 그리고 Gevent 등으로 지원하고 있죠.

자세한 내용은 마찬가지로 Document 를 확인하면 됩니다.

따라서, 전형적인 프로세스 기반 worker를 사용할 때, worker를 재시작한다는 것은 단순히 프로세스를 죽이고 새로 만드는 것입니다. 스레드라면 훨씬 더 가벼워 지겠죠. 정확이 제가 원하던 것이었습니다. 그런데 문제는... 이 옵션을 사용하여도 극히 일부분에서만 Auto-Reloading이 적용되는 것입니다!!! 😵‍💫🤮

정말 별 수를 다 써봐도 해결되지도 않고 원인도 찾지 못했습니다......(아시는 분은 댓글좀요)

결과

결과적으로는 --reload_extra_files 라는 옵션으로 해결할 수 있었습니다. 이 옵션은 말 그대로 reload에 반영될 파일들을 직접적으로 명시할 수 있는 옵션입니다. 그런데, 맘에 들지 않지만 울며 겨자 먹기로 했습니다. 왜냐하면 공식 문서에 따르면 기본적인 모듈들은 이미 reload에서 반영된다고 가정하고, 이 --reload_extra_files는 templates, configurations와 같이 어플리케이션 파일이 아닌 정적인 요소를 담는 파일을 위해 만들어진 것이기 때문입니다.

하지만, 방법이 없었습니다! 이 옵션이라도 있어서 다행이지요...

여러 개의 모듈(파일)을 다 커맨드에 입력할 수는 없으니 --config 란 옵션을 통해서 아래와 같이 여러 Gunicorn 옵션들을 하나의 파이썬 파일, 즉 Configuration으로 저장하고 실행하는 것이 좋습니다.

# conf 파일 예시
bind = ":8001"
env = ["DJANGO_SETTINGS_MODULE=site.settings"]
workers = 4
timeout = 3 
reload = True
reload_engine = "poll"
reload_extra_files = ["/site/site/urls.py", ...]

끝까지 킹 받기...

아니 근데 마지막까지 킹 받는 점이 있습니다. 여러 분이 Django를 한 번이라도 써봤다면 Django에서는 각 기능을 별로 분리하여 각 앱에 views.py, urls.py, models.py 등을 만드는 것을 알겁니다. 그래서, 저도 reload_extra_files를 명시할 때 당연히

/site/site/* 와 같이 wildcard 표기를 활용해서 앱 내에 위치한 전체 모듈을 넣어주려 했습니다.

그런데, 안 먹습니다!!!

시....실화? 진짜로 Gunicorn 레포지토리에서 이슈를 찾아보니 이미 5년 전에 그것도 한국 분께서!!! PR을 올린 부분이더라고요~https://github.com/benoitc/gunicorn/pull/1846

Gunicorn의 owner와 collaborator도 매우 긍정적으로 해당 PR 바라보신 거 같은데 여러 논의 + PR 올리신 한국 분께서 오랜 기간 활동 놓치신 관계로 아직도 Open 상태로 머물러 있네요. 얼른 머지 시키라는 저와 같은 마음의 분들이 계시는데, 한 번 두고 봅시다...ㅋㅋㅋㅋㅋㅋ

profile
소프트웨어 엔지니어

0개의 댓글