import argparse import gc import os import psutil import uvicorn from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from loguru import logger from starlette.responses import JSONResponse from routers import router from routers import classifier from utils.classifier_model_store import get_model app = FastAPI(title="classifier_service") app.state.request_counter = 0 app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(router) # app.include_router(classifier.router) # ── 로거 설정 ───────────────────────────────────── logger.remove() logger.add( "logs/{time:YYYY-MM-DD}.log", level="DEBUG", rotation="00:00", retention="30 days", format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}", ) # ── 메모리 유틸 ─────────────────────────────────── def log_memory_usage() -> float: process = psutil.Process(os.getpid()) return process.memory_info().rss / 1024 / 1024 # ── HTTP 미들웨어 ───────────────────────────────── @app.middleware("http") async def log_requests(request: Request, call_next): try: memory_before = log_memory_usage() request_counter = getattr(app.state, "request_counter", 0) + 1 app.state.request_counter = request_counter logger.info(f"request_counter: {request_counter}") logger.info(f"Received: {request.method} {request.url}") logger.info(f"Headers: {dict(request.headers)}") response = await call_next(request) logger.info(f"Response status: {response.status_code}") if request_counter % 100 == 0: logger.info("gc.collect 실행") gc.collect() memory_after = log_memory_usage() logger.info( f"Memory: Before={memory_before:.2f}MB, " f"After={memory_after:.2f}MB, " f"Diff={memory_after - memory_before:.2f}MB" ) return response except Exception as e: logger.exception(f"요청 처리 중 예외 발생: {e}") return JSONResponse( status_code=500, content={"detail": "Internal Server Error", "error": str(e)}, ) @app.get("/", tags=["기타"]) async def root(): return {"message": "document classifier service"} @app.get("/health", tags=["기타"]) async def health(): m = get_model() return { "status": "ok", "model_loaded": m is not None, "classes": list(m.classes_) if m else [], } # ── 진입점 ──────────────────────────────────────── if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("-host", default="0.0.0.0") parser.add_argument("-port", default=10941) args = parser.parse_args() logger.info(f"서버 시작: {args.host}:{args.port}") uvicorn.run( app, host=args.host, port=int(args.port), limit_concurrency=1000, timeout_keep_alive=120, log_level="debug", )