"""naver-fetch FastAPI entry — lifespan(fetch_loop + heartbeat_loop) + /health.""" from __future__ import annotations import asyncio import logging from contextlib import asynccontextmanager import redis.asyncio as aioredis from fastapi import FastAPI import fetch_worker from config import load_settings from nas_client import NASClient from naver_client import NaverClient logging.basicConfig(level=logging.INFO, format="%(asctime)s %(name)s %(levelname)s %(message)s") logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): settings = load_settings() nas = NASClient(settings.nas_base_url, settings.internal_api_key) naver = NaverClient(settings.naver_real_estate_type, settings.naver_token_url, settings.naver_headless) state = fetch_worker.FetchState() redis = aioredis.from_url(settings.redis_url, decode_responses=False) ft = asyncio.create_task(fetch_worker.fetch_loop(nas, naver, state, settings)) hb = asyncio.create_task(fetch_worker.heartbeat_loop(redis, state)) logger.info("naver-fetch lifespan 시작") try: yield finally: for t in (ft, hb): t.cancel() try: await t except asyncio.CancelledError: pass await naver.close() await nas.close() await redis.aclose() logger.info("naver-fetch lifespan 종료") app = FastAPI(lifespan=lifespan) @app.get("/health") def health(): return {"ok": True, "service": "naver-fetch"}