From 351db312ee9997935a2c8f6e281f7f839e8c56c4 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 7 Sep 2026 06:30:37 +0900 Subject: [PATCH] =?UTF-8?q?perf(main):=20=EC=9E=90=EB=8F=99=20=EB=A6=AC?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=EA=B0=80=20=ED=9B=91=EB=8A=94=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=EB=A5=BC=20=EC=86=8C=EC=8A=A4=EB=A7=8C=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=A2=81=ED=9E=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uvicorn StatReload 는 0.25초마다 지정 폴더를 rglob("*.py") 로 재귀로 훑는데, 폴더를 안 주면 현재 폴더가 대상이라 storage(27GB) · venv(파이썬 파일만 7,530개) · node_modules 까지 통째로 돌고 있었음. 파이썬이 실제로 사는 폴더 14개만 감시하게 함(산출물·의존성·백업 제외). 루트는 넣지 않음 — 넣으면 재귀라 도로 다 훑음. 그 대신 main.py 를 고칠 때는 서버를 손으로 다시 띄워야 함. ⚠ 이 변경이 「요청 없는 서버가 CPU 70%」를 고치지는 못했음. 그 CPU 는 감시 프로세스(0%)가 아니라 **앱 프로세스** 쪽이며 원인 미상 — 계획서에 남겼음. 이 커밋은 감시 낭비만 걷어낸 것임. Co-Authored-By: Claude Opus 5 (1M context) --- main.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/main.py b/main.py index 5f1affd8..74b4aea3 100644 --- a/main.py +++ b/main.py @@ -493,6 +493,49 @@ app.include_router(b08_quantity_router, dependencies=protected_with_company) # ───────────────────────────────────────────────────────────────────────── # 앱 실행 # ───────────────────────────────────────────────────────────────────────── +def _reload_dirs() -> list[str]: + """자동 리로드가 **훑을 폴더만** 골라 준다 — 폴더째 주면 서버가 쉬는 중에도 CPU를 먹는다. + + uvicorn 의 StatReload 는 0.25초마다 지정 폴더를 통째로 훑는다. 아무것도 안 주면 + 현재 폴더가 대상이 되는데, 여기에는 `storage`(27GB · 프로젝트 산출물)와 `tmp`·`venv`· + `node_modules` 가 함께 들어 있다. 그래서 **요청이 하나도 없는 서버가 CPU 70%** 를 물고 + 있었고, 창 둘이 각각 그러니 기기가 늘 140% 눌린 채였다(2026-09-07 실측). 속도 계측이 + 회차마다 3배씩 흔들린 원인도 이것이다. + + 파이썬이 실제로 사는 폴더만 준다 — 화면 코드(TS)는 vite 가 따로 본다. + """ + root = Path(__file__).resolve().parent + # ⚠ 루트 자체는 넣지 않는다 — uvicorn 은 준 폴더를 `rglob("*.py")` 로 **재귀**로 훑으므로 + # 루트를 주면 storage·venv(파이썬 파일만 7,530개)를 도로 다 훑는다. 그 대신 `main.py` + # 를 고칠 때는 서버를 손으로 다시 띄워야 한다(자주 있는 일이 아님). + watched: list[str] = [] + for entry in sorted(root.iterdir()): + if not entry.is_dir() or entry.name.startswith(".") or entry.name in _RELOAD_SKIP: + continue + if any(entry.rglob("*.py")): + watched.append(str(entry)) + return watched + + +# 파이썬이 있어도 훑지 않을 폴더 — 산출물·의존성·백업. +_RELOAD_SKIP = { + "storage", + "tmp", + "venv", + "node_modules", + "__pycache__", + "log", + "docs", + "resources", + "scratch", + "graphify-out", + "0_old", + "db_management", + "migrations", + "ui_template", +} + + if __name__ == "__main__": import uvicorn @@ -502,5 +545,7 @@ if __name__ == "__main__": host=SERVER_HOST, port=SERVER_PORT, reload=DEBUG, + # 폴더를 좁히지 않으면 리로더가 storage(27GB)까지 0.25초마다 훑는다 — 위 주석 참조. + reload_dirs=_reload_dirs() if DEBUG else None, access_log=False, )