Commit Graph

54 Commits

Author SHA1 Message Date
민헌
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
민헌
da9bd7750c feat(lps): 작업 큐 엔진 — PostgreSQL 원자적 claim + lease + dead-letter
레퍼런스의 DB-큐 반면교사를 전부 뒤집는 큐 엔진을 구축한다.
 - 원자적 claim: FOR UPDATE SKIP LOCKED 서브쿼리 + 같은 UPDATE + RETURNING
   → 워커 다수여도 이중 할당 원천 불가(fetch/claim 미분리)
 - 모든 전이는 조건부 CAS(status/worker_id 가드) + RETURNING
 - 복구는 timeout 추측이 아닌 lease 만료 소유권 기반(reaper 회수)
 - 재시도 지수백오프 + max_attempts + dead-letter 를 큐에 내장(스크립트 난립 제거)
 - dedupe_key 부분 유니크로 활성 중복 차단, counts()로 관측(수동 psql 대체)

- enums: JobStatus(PENDING/RUNNING/DONE/DEAD)·JobType(SEARCH/OUTBOX)
- models: job 테이블(무FK·SMALLINT코드·TIMESTAMPTZ, claim/lease/dedupe 인덱스)
- crud/job_crud: JobQueue(enqueue/claim/complete/fail/renew_lease/reap/counts)
- tests: 동시 8워커 이중할당0·lease회수·재시도→dead·소유권가드 등 8건(실 lps_db)

부수: 포트 9400→9600 (negodata 9400 충돌 회피)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 16:37:32 +09:00
민헌
e27b73c018 feat(lps): 쿠팡 검색 어댑터 — Akamai 우회(Patchright) + 정규화 파서
소스 어댑터 패턴으로 크롤링을 시작한다. 쿠팡은 Akamai Bot Manager 의
JS 행동 챌린지라 curl_cffi 단독 불가 → Patchright(스텔스 Playwright) +
실제 Chrome(channel=chrome)으로 챌린지를 통과하고 selectolax 로 파싱한다.

- contract: SearchAdapter(ABC)·NormalizedProduct·AdapterHealth·AdapterError
- coupang: adapter(브라우저 재사용, 챌린지 1회)·parser(순수)·selectors(외부화, webpack 해시 prefix 매칭)
- 공용: rate_limiter(2~8s 랜덤)·proxy(무프록시 off 인터페이스)·util.parse_price
- 가격 파싱: 단위가격 '(1개당 44,400원)'의 앞 '1' 오인 방지 — '원' 앞 숫자 앵커링
- deps: curl_cffi·selectolax·patchright(nodriver 는 py3.14 버그로 대체)
- tests: 파서 회귀(소형 fixture) — 라이브 2회 검색 + 파서 3/3 통과

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 15:59:48 +09:00
민헌
11a7be7154 feat(lps): 인터넷 최저가 검색 솔루션 프레임워크 골격 추가
backend 와 동일한 프레임워크로 lps/ 폴더를 신설한다. 구체적인 도메인
로직(크롤링/오픈API/최저가 산정)은 미정이라 골격만 구성한다.

- FastAPI 부트스트랩(web_main/router) + lifespan·CORS·gzip·로그 미들웨어 + /healthz
- TOML 설정 로더(APP_ENV) + pydantic config + DB env override
- DB 세션 매니저(논리 DB × R/W, service→람다 위임) — 엔진 lazy 라 DB 없이도 부팅
- 공통 응답 규약(gmodel) + ErrorType/DBType/DBWRType
- router→services→crud 계층 컨벤션(services/crud 는 빈 폴더로 자리만)
- 포트 9400(backend 9300·agent 9500 회피), Dockerfile/run_local_server.sh/README
- tests/test_health.py 스모크(healthz, DB 없이 통과)

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