Files
matchmaking-v2/tests/test_search_retry.py
raulgupta 538d2fc5f3 Retry-on-empty guard for scrape-flaky boards
RCA of a prod "Naukri returned 0" on an AI-Architect search: NOT a cursor issue (cursors removed;
naukri-feed is a date feed with no page param), NOT a city-name or keyword bug — the EXACT same input
flaked 0 then returned 15 on retry. The scrape-based actors (Naukri-feed, curious_coder LinkedIn)
intermittently return 0 under the site's anti-scrape rate-limiting, then recover.

Fix: _fetch_board retries a board ONCE (fresh) when it returns 0. One guard covers BOTH the Naukri and
LinkedIn intermittency (cleaner than per-board fallbacks). A genuinely-empty query just returns 0 again
(cheap). 67 tests pass (3 new: recovers transient 0, no retry on success, no infinite loop).
2026-06-26 17:05:30 +05:30

52 lines
2.1 KiB
Python

"""Retry-on-empty guard — scrape-flaky boards (Naukri-feed, curious_coder LinkedIn) intermittently
return 0; one fresh retry rescues the transient case. RCA: the same input flaked 0 then returned 15."""
import asyncio
from app.engine import search
def _run(coro):
return asyncio.run(coro)
def test_retry_on_empty_recovers_transient_zero(monkeypatch):
calls = {"n": 0}
async def fake_run_actor(actor, inp, cache_mode=None):
calls["n"] += 1
# first call flakes (0), retry returns a real job
if calls["n"] == 1:
return []
return [{"profile_job_title": "Data Architect", "branch_company_name": "Acme",
"branch_location_city_name": "Delhi", "skills": ["python"], "job_id": "1"}]
monkeypatch.setattr(search, "run_actor", fake_run_actor)
key, jobs = _run(search._fetch_board("workindia", {"title": "Data Architect", "location": ["Delhi · India"]}))
assert calls["n"] == 2, "a board returning 0 must be retried exactly once"
assert len(jobs) == 1, "the retry's jobs are used"
def test_no_retry_when_first_call_succeeds(monkeypatch):
calls = {"n": 0}
async def fake_run_actor(actor, inp, cache_mode=None):
calls["n"] += 1
return [{"profile_job_title": "X", "branch_company_name": "Y",
"branch_location_city_name": "Delhi", "skills": [], "job_id": "1"}]
monkeypatch.setattr(search, "run_actor", fake_run_actor)
_run(search._fetch_board("workindia", {"title": "X", "location": ["Delhi · India"]}))
assert calls["n"] == 1, "a board that returns jobs is NOT retried (no extra cost)"
def test_genuinely_empty_returns_empty_after_one_retry(monkeypatch):
calls = {"n": 0}
async def fake_run_actor(actor, inp, cache_mode=None):
calls["n"] += 1
return [] # genuinely empty (e.g. WorkIndia for a tech role)
monkeypatch.setattr(search, "run_actor", fake_run_actor)
key, jobs = _run(search._fetch_board("workindia", {"title": "AI Architect", "location": ["Delhi · India"]}))
assert calls["n"] == 2 and jobs == [], "retry once, then accept the empty result (no infinite loop)"