From 77a36c43d4da493270065228505b37aa9c64c9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=ED=97=8C?= Date: Thu, 9 Jul 2026 21:06:29 +0900 Subject: [PATCH] =?UTF-8?q?fix(lps):=20gmarket=20=EC=9B=9C=EC=97=85=20?= =?UTF-8?q?=EC=8B=A0=EB=A2=B0=EC=84=B1=20=E2=80=94=20=EB=82=98=EC=81=9C=20?= =?UTF-8?q?IP=20=EC=8B=9C=20=ED=9A=8C=EC=A0=84=20=EC=9E=AC=EC=8B=9C?= =?UTF-8?q?=EB=8F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 웜업이 인터랙티브 Turnstile(IP 평판 나쁨)로 실패하면 다른 IP 로 회전해 최대 3회 재시도. gmarket 커버리지 플래키함 완화(100 IP 풀에서 좋은 IP 를 찾을 확률↑). Co-Authored-By: Claude Fable 5 --- lps/worker_main.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lps/worker_main.py b/lps/worker_main.py index 30ae912..7da5b3f 100644 --- a/lps/worker_main.py +++ b/lps/worker_main.py @@ -65,17 +65,23 @@ def _build_worker(i: int, concurrency: int, has_openai: bool, neg_cache, history return handler, list(adapters.values()) + list(fallback_adapters.values()) -async def _warmup_worker(worker_adapters): - """워커의 챌린지 소스(Turnstile/Akamai)를 미리 1회 풀어 쿠키(cf_clearance 등)를 확보한다. - 콜드 비용을 시작 시 1회로 몰아, 이후 실 작업은 웜(빠름). 백그라운드로 돌려 잡 처리를 막지 않는다.""" +async def _warmup_worker(worker_adapters, tries: int = 3): + """워커의 챌린지 소스(Turnstile/Akamai)를 미리 풀어 쿠키(cf_clearance 등)를 확보한다. + 콜드 비용을 시작 시 몰아, 이후 실 작업은 웜(빠름). 백그라운드로 돌려 잡 처리를 막지 않는다. + 나쁜 IP 는 인터랙티브 Turnstile 로 에스컬레이션되므로, 실패 시 **다른 IP 로 회전 재시도**한다.""" for ad in worker_adapters: if ad.source not in ("gmarket", "auction", "coupang"): continue - try: - await ad.search("생수", limit=1) - LOG.i(f"[warmup:{ad.source}] 챌린지 통과·쿠키 확보") - except Exception as ex: - LOG.w(f"[warmup:{ad.source}] 실패(무시, 첫 잡에서 재시도): {type(ex).__name__}") + for attempt in range(tries): + try: + await ad.search("생수", limit=1) + LOG.i(f"[warmup:{ad.source}] 챌린지 통과·쿠키 확보 (시도 {attempt + 1})") + break + except Exception as ex: + if attempt < tries - 1: + ad._rotate_ip(f"웜업 재시도({type(ex).__name__}) — 새 IP") + else: + LOG.w(f"[warmup:{ad.source}] {tries}회 실패(첫 잡에서 재시도): {type(ex).__name__}") async def run_browser_reaper(adapters, stop, idle_sec: float = 120.0, interval: float = 30.0):