o2o-negosium-original/lps/tests
민헌 152aed9908 fix(lps): 한 소스가 막혀도 잡을 정상 종료 — '탐색 중'에서 멈추던 원인
운영 로그(2026-08-06)에서 드러난 문제. 쿠팡이 막힌 동안 **네이버가 매번 40건을 가져왔는데도**
잡이 전부 DEAD 로 갔다:

  fail 3c0bcaff → DEAD ({'coupang': {'error': 환경 차단}, 'naver': {'count': 40}})

그리고 DEAD 는 price_history 에 행을 남기지 않는다. 이를 폴링하는 negodata 최저가 모달은
받을 결과가 영영 없어 '탐색 중'에서 멈춘다(사용자 화면 확인). 즉 프론트 버그가 아니라
**백엔드가 답을 안 준 것**이다 — 두 증상이 같은 뿌리였다.

원인: 핸들러가 '하나라도 실패했나'(bool)만 보고 무조건 raise 했다. 한 소스가 막혔다고
다른 소스가 멀쩡히 가져온 결과까지 버린 셈이다.

바꾼 것:
- _search_round 가 **성공한 소스 목록**을 돌려준다(bool → list).
- 살아있는 소스가 하나라도 있으면 그 결과로 진행한다. **전부 죽었을 때만** 재시도한다
  ('없음'이라 단정할 수 없는 건 그때뿐이다).
- 결과에 sources_ok/sources_failed/partial 을 실어 커버리지를 드러낸다(부분 결과 로그도 남김).
- 부분 실패 상태의 not_found 는 **네거티브 캐시에 넣지 않는다** — 막힌 소스엔 있었을 수 있는데
  '없음'으로 굳히면 TTL 동안 재검색이 막힌다(사용자가 '다시 검색'을 눌러도 캐시 히트).
- 전부 실패 + 재시도 소진이면 DEAD 대신 outcome='error' 로 **이력을 남기고** 종료한다.
  화면이 무한 대기 대신 결과를 받는 게 중요하다.

negodata 는 변경 없이 받는다(outcome='error' → success_yn=false, fail_reason='error').

테스트 5건 추가·1건 갱신(옛 계약 '한 소스 실패 시 raise' 를 새 계약으로 교체), 전체 274 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 16:34:36 +09:00
..
fixtures feat(lps): 네이버 최저가를 모바일 크롤로 복구(오픈API 종료 대체) 2026-08-05 09:05:38 +09:00
test_admin_api.py feat(lps): 관리자 FE 용 API 6종 — 잡 목록/재큐·상품 목록·IP세션/차단/비용 통계 2026-07-13 21:42:38 +09:00
test_alerts.py feat(lps): 네이버 회수율 48→120건(적응형 스크롤) + 크롤 차단을 기동 즉시 알림 2026-08-05 13:33:19 +09:00
test_api_guard.py refactor(lps): 설정을 TOML 단일 소스로 통합 — env/.env 이중 관리 제거 2026-07-13 21:11:31 +09:00
test_bot_detection.py feat(lps): 봇 감지 시 IP 회전+재시도 + 감지 이력 기록 2026-07-09 11:04:07 +09:00
test_browser_base.py fix(lps): 풀 고갈 시 남의 IP 를 빌려 쓰던 문제 — 임대 없으면 크롤하지 않는다 2026-08-06 12:01:15 +09:00
test_coupang_parser.py feat(lps): 배송 표기 원문 기록 — 순위는 상품가 유지, 배송은 근거로 남긴다 2026-08-05 14:40:00 +09:00
test_fingerprint.py fix(lps): 네이버 컨테이너 차단 — 계측 CDP 토글 + 지문 판정 + 폰트 보강 2026-08-06 15:22:01 +09:00
test_health.py feat(lps): 인터넷 최저가 검색 솔루션 프레임워크 골격 추가 2026-07-08 15:18:27 +09:00
test_ip_session.py feat(lps): IP 선제 로테이션 — 요청 예산·포트 쿨다운·ip_session 관측 2026-07-13 16:35:44 +09:00
test_job_queue.py feat(lps): 알림 룰 4종 추가 — 데드라인·검색원가·포트 고갈·예산 누수 2026-07-13 17:29:08 +09:00
test_lps_api.py feat(lps): 알림 룰 4종 추가 — 데드라인·검색원가·포트 고갈·예산 누수 2026-07-13 17:29:08 +09:00
test_naver_hub.py feat(lps): NCP NAVER API HUB 쇼핑 인사이트 클라이언트 추가 2026-08-04 11:23:26 +09:00
test_naver_shop_parser.py feat(lps): 배송 표기 원문 기록 — 순위는 상품가 유지, 배송은 근거로 남긴다 2026-08-05 14:40:00 +09:00
test_negative_cache.py feat(lps): 재시도/못찾음 완결 로직 — 재정제 루프 + not_found + 네거티브 캐시 2026-07-09 09:12:47 +09:00
test_openmarket_parser.py perf(lps): Step2/3 — Turnstile 웜업·동적 차단 + 유휴 브라우저 정리 2026-07-09 20:20:58 +09:00
test_pipeline.py feat(lps): 네이버 몰별 최저가 분해(by_mall) — 오픈마켓 가시화 2026-07-09 13:59:15 +09:00
test_pool_autosize.py feat(lps): process_count 기반 커넥션 풀 자동 산정 — 멀티코어 풀 오버서브스크립션 방지 2026-07-09 23:59:05 +09:00
test_port_lease.py fix(lps): 풀 고갈 시 남의 IP 를 빌려 쓰던 문제 — 임대 없으면 크롤하지 않는다 2026-08-06 12:01:15 +09:00
test_port_registry.py feat(lps): IP 를 태우지 말고 한계 직전까지 쓰고 쉬게 — 네이버 예산 상향 + 휴식 개념 2026-08-05 11:16:37 +09:00
test_price_history.py feat(lps): 최저가 오퍼의 신뢰 신호(평점·리뷰) 수집 — 네이버·쿠팡 공통 2026-08-05 14:00:12 +09:00
test_profile_slot.py feat(lps): 포트(IP) 장부를 DB 로 올려 멀티 프로세스에서 안전하게 — 프로필 슬롯도 분리 2026-08-05 11:44:54 +09:00
test_proxy.py feat(lps): IP 선제 로테이션 — 요청 예산·포트 쿨다운·ip_session 관측 2026-07-13 16:35:44 +09:00
test_search_handler.py fix(lps): 한 소스가 막혀도 잡을 정상 종료 — '탐색 중'에서 멈추던 원인 2026-08-06 16:34:36 +09:00
test_similarity_judge.py fix(lps): AI 매칭이 후보 많으면 통째로 무너지던 문제 — 배치 분할 + 규칙 충돌 제거 2026-08-05 15:45:32 +09:00
test_user_agent.py fix(lps): 네이버 컨테이너 차단 해결 — 원인은 UA 의 플랫폼 토큰이었다 2026-08-06 15:40:14 +09:00
test_worker.py fix(lps): 워커 행(hang) 3중 방어 — 잡 데드라인·웜업 타임아웃·정리 루프 격리 2026-07-10 11:27:03 +09:00