Merge remote-tracking branch 'origin/sub_desktop_1' into main_desktop_1
This commit is contained in:
@@ -168,6 +168,27 @@ def _kill_process_tree(pid: int) -> None:
|
||||
logger.debug("[Frontend] 프로세스 정리 중 무시된 예외: %s", exc)
|
||||
|
||||
|
||||
def _dev_port_listening(port: int) -> bool:
|
||||
"""개발 서버(Vite)가 이미 그 포트를 물고 있나.
|
||||
|
||||
**리로드인지 첫 기동인지를 가르는 하나뿐인 표식**이다. uvicorn 리로더는 코드가 바뀌면
|
||||
앱 프로세스만 다시 띄우고 Vite 자식은 그대로 두므로, 포트가 살아 있으면 리로드다.
|
||||
환경변수 같은 별도 깃발을 두지 않는 까닭은 그것이 **실제와 어긋날 수 있기** 때문이다 —
|
||||
포트는 어긋나지 않는다.
|
||||
"""
|
||||
import socket
|
||||
|
||||
probe = socket.socket()
|
||||
probe.settimeout(0.5)
|
||||
try:
|
||||
probe.connect(("127.0.0.1", port))
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
finally:
|
||||
probe.close()
|
||||
|
||||
|
||||
def _free_dev_port(port: int) -> None:
|
||||
"""개발 서버 포트를 물고 있는 잔여 프로세스를 정리한다.
|
||||
|
||||
@@ -234,8 +255,22 @@ def serve_frontend_dev() -> None:
|
||||
|
||||
|
||||
def stop_frontend_dev() -> None:
|
||||
"""앱이 내려갈 때 개발 서버도 같이 내린다 — 유령 인스턴스를 남기지 않는다."""
|
||||
"""앱이 내려갈 때 개발 서버도 같이 내린다 — 유령 인스턴스를 남기지 않는다.
|
||||
|
||||
⚠⚠ **개발 중에는 내리지 않는다** (2026-09-12 실측으로 드러난 고리).
|
||||
uvicorn 리로더는 `*.py` 가 바뀔 때마다 앱 프로세스를 갈아 끼운다. 그때 여기서
|
||||
Vite 를 죽이면 **새 프로세스는 「Vite 가 없다」고 보고 `npm run build` 를 처음부터
|
||||
다시 돌린다**(최대 300초 + B07 CAD). 그 사이 화면은 뜨지 않고 `/api/health` 는
|
||||
`stale: true` 인 채로 옛 코드를 계속 내준다 — 그날 리로드가 두 번 멈췄고 한 번은
|
||||
두 시간 반 동안 안 끝났다. **옛 화면을 보고 헛검증하게 만드는 자리다.**
|
||||
⇒ Vite 는 **한 앱 프로세스가 아니라 개발 세션의 것**이다. 살려 두고 다음 기동이
|
||||
그대로 물려쓴다(`_dev_port_listening`). 남은 유령은 다음 기동의
|
||||
`_free_dev_port` 가 포트로 잡아 정리하므로 쌓이지 않는다.
|
||||
"""
|
||||
global _frontend_dev_process
|
||||
if ENVIRONMENT == "development":
|
||||
logger.info("[Frontend] 개발 서버는 살려 둔다 — 다음 기동이 그대로 물려쓴다")
|
||||
return
|
||||
if _frontend_dev_process is None:
|
||||
return
|
||||
logger.info("[Frontend] 개발 서버 종료 (pid %s)", _frontend_dev_process.pid)
|
||||
@@ -293,12 +328,23 @@ async def lifespan(app: FastAPI):
|
||||
datetime.fromtimestamp(_CODE_MTIME_AT_START).isoformat(timespec="seconds"),
|
||||
)
|
||||
|
||||
# 프론트엔드 빌드 (필수)
|
||||
build_frontend()
|
||||
|
||||
# 개발 환경에서 개발 서버 실행 (선택사항)
|
||||
if ENVIRONMENT == "development":
|
||||
serve_frontend_dev()
|
||||
# ⚠⚠ **리로드마다 프론트를 다시 빌드하지 않는다** (2026-09-12 실측으로 드러난 자리).
|
||||
# uvicorn 리로더는 `*.py` 가 바뀔 때마다 이 lifespan 을 다시 탄다. 그때마다
|
||||
# `npm run build`(최대 300초, B07 CAD 빌드까지 딸림)가 돌고 Vite 를 죽였다 살리느라
|
||||
# **리로드가 몇 분씩 걸리거나 아예 멈춘다** — 그날 두 번 멈췄고 한 번은 두 시간 반 동안
|
||||
# 안 끝나, `/api/health` 가 `stale: true` 인 채로 옛 코드를 계속 내주었다.
|
||||
# ⇒ **옛 화면을 보고 헛검증하게 만드는 자리라 그냥 느린 것이 아니다.**
|
||||
# 개발 중에는 Vite 가 HMR 로 이미 최신을 내주므로 다시 빌드할 까닭이 없다.
|
||||
if ENVIRONMENT == "development" and _dev_port_listening(FRONTEND_DEV_PORT):
|
||||
logger.info(
|
||||
"[Frontend] 개발 서버가 %d 포트에 이미 살아 있음 — 빌드·재기동 건너뜀(리로드)",
|
||||
FRONTEND_DEV_PORT,
|
||||
)
|
||||
else:
|
||||
# 첫 기동(또는 프로덕션) — 여기서만 빌드한다.
|
||||
build_frontend()
|
||||
if ENVIRONMENT == "development":
|
||||
serve_frontend_dev()
|
||||
|
||||
# DB 풀 초기화
|
||||
await init_db_pool()
|
||||
|
||||
Reference in New Issue
Block a user