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):