커머스 검색요청 계약을 프레임워크(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>
40 lines
1.5 KiB
Python
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())
|