o2o-negosium-original/lps/router/v1/lps/search.py
민헌 bebb6a71e6 feat(lps): 검색 API 라우터 — 요청 적재(enqueue) + 상태/큐 통계 조회
커머스 검색요청 계약을 프레임워크(protocol+service+RemoveNoneResponse)로 재구성.
실제 검색은 워커가 큐에서 꺼내 수행하도록 API 는 적재까지만 담당(비동기 분리).

- POST /v1/lps/search: 상품 리스트 → 상품별 SEARCH 잡 적재, product_code 로 활성 중복 방지, job_type→우선순위 매핑
- GET /v1/lps/jobs/{job_id}: 잡 상태/시도/결과 조회
- GET /v1/lps/queue/stats: 상태별 카운트(모니터링)
- protocol/lps_service 추가, job_crud.get() 단건조회, enums LPS_JOB_NOT_FOUND
- tests: 적재/중복/상태/미존재/통계 5건 (ASGI 클라이언트 + 실 lps_db) → 전체 16/16

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 16:49:28 +09:00

40 lines
1.5 KiB
Python

"""LPS 검색 API 라우터. 요청 적재(enqueue) + 잡 상태/큐 통계 조회."""
from fastapi import APIRouter, Depends
from router.v1.validator.dependencies import RemoveNoneResponse
from services.lps_service import LpsService
from router.v1.lps.protocol import Res_JobStatus, Res_QueueStats, Res_Search, Req_Search
router = APIRouter(prefix="/v1/lps", tags=["LPS"], responses={404: {"description": "Not found"}})
@router.post(
path="/search",
response_model=Res_Search,
summary="최저가 검색 요청",
description="상품 리스트를 받아 상품별 검색 잡을 큐에 적재한다(product_code 로 활성 중복 방지). 실제 검색은 워커가 비동기 수행.",
)
async def search(req: Req_Search, service: LpsService = Depends()):
return RemoveNoneResponse(await service.submit_search(req.data))
@router.get(
path="/jobs/{job_id}",
response_model=Res_JobStatus,
summary="잡 상태 조회",
description="적재된 검색 잡의 상태/시도횟수/결과를 조회한다.",
)
async def job_status(job_id: str, service: LpsService = Depends()):
return RemoveNoneResponse(await service.get_job(job_id))
@router.get(
path="/queue/stats",
response_model=Res_QueueStats,
summary="큐 상태 카운트",
description="상태별(PENDING/RUNNING/DONE/DEAD) 잡 개수. 관리/모니터링용.",
)
async def queue_stats(service: LpsService = Depends()):
return RemoveNoneResponse(await service.stats())