perf(setup): setup 미들웨어 user COUNT 캐시 — per-request 쿼리 제거 (R10)
setup 완료 후에도 모든 비-bypass 요청이 select count(User.id) 를 실행하던 per-request 비용. 셋업 완료(user 존재)는 monotonic 이라 1회 확인 후 _setup_complete 플래그로 영구 skip(이후 요청 DB 쿼리 0). global 선언은 함수 첫 줄(read+assign 혼용 UnboundLocalError 방지). R10 잔여(library-tree jsonb 집계 golden-diff·facet-counts·events-count·synthesis cache TTL)는 결과 동등성 검증 동반이라 후속. 검증: py_compile 통과. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+9
-3
@@ -240,21 +240,27 @@ SETUP_BYPASS_PREFIXES = (
|
||||
"/api/setup", "/api/config", "/setup", "/health", "/docs", "/openapi.json", "/redoc",
|
||||
)
|
||||
|
||||
# R10: 셋업 완료(user 존재)는 단조(monotonic) — 한 번 확인되면 영구. 매 요청 COUNT 쿼리
|
||||
# 대신 캐시 플래그로 전환 (setup 후 모든 요청이 users COUNT 하던 per-request 비용 제거).
|
||||
_setup_complete = False
|
||||
|
||||
|
||||
@app.middleware("http")
|
||||
async def setup_redirect_middleware(request: Request, call_next):
|
||||
global _setup_complete # 함수 내 read+assign 둘 다 모듈 전역 참조 (UnboundLocalError 방지)
|
||||
path = request.url.path
|
||||
# 바이패스 경로는 항상 통과
|
||||
if any(path.startswith(p) for p in SETUP_BYPASS_PREFIXES):
|
||||
# 셋업 완료됐거나 바이패스 경로면 즉시 통과 (DB 쿼리 없음)
|
||||
if _setup_complete or any(path.startswith(p) for p in SETUP_BYPASS_PREFIXES):
|
||||
return await call_next(request)
|
||||
|
||||
# 유저 존재 여부 확인
|
||||
# 유저 존재 여부 확인 (셋업 완료 전 1회성 — 완료 확인되면 플래그 set 후 영구 skip)
|
||||
try:
|
||||
async with async_session() as session:
|
||||
result = await session.execute(select(func.count(User.id)))
|
||||
user_count = result.scalar()
|
||||
if user_count == 0:
|
||||
return RedirectResponse(url="/setup")
|
||||
_setup_complete = True
|
||||
except Exception:
|
||||
pass # DB 연결 실패 시 통과 (health에서 확인 가능)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user