SPB Git

spb/lou-ka

Public

Lou·Ka — tous les logements à louer du Québec, un seul endroit.

[ka2] fix connecteur sotramont: hoquets « 200 sans cartes » récurrents retryables sur le portfolio. Au sync de 21:18 le connecteur a échoué (stale) sur une page 200 servie SANS cartes article.c--article-project — 2e épisode du même hoquet (10-17, conclu « rien à faire » : il revient), alors que le connecteur est sain (found=8 stable, re-testé live : 200, 152 occurrences de c--article-project, fetch venv → 8 unités). Le retry du fix 09-21 ne couvrait que l'échec du GET : un 200 vide partait directement en erreur franche et tuait le sync sur un hoquet isolé. Fix minimal (patron morin ae6ac03 / groupe_robin 3f5c9dc) : la boucle de retry ×3 (backoff 0/3/6 s) couvre désormais AUSSI le cas « GET ok mais 0 carte » ; erreurs franches inchangées après 3 échecs (pas de zéro silencieux), distinction conservée entre portfolio inaccessible et gabarit remanié. Fixtures inchangées, pytest sotramont 2 passed. Testé : fetch() venv → 8 unités (Pointe-Claire 3, Mascouche 2, Repentigny 2, Saint-Laurent 1 ; 1 460-1 970 $), run.py sync sotramont → found=8 ok (added=0, updated=0, removed=0, 1,4 s) = médiane exacte 8.0, pm2 restart lou-ka-sync, site :8095 → 200.

Simon-Pierre Boucher committed (Oct 30, 2026) parent 3f5c9dc Browse files

1 changed file +21 −17

Unified Split
modified louka/connectors/sotramont.py +21 −17
@@ -52,32 +52,36 @@ class SotramontConnector(BaseConnector):
52 52
53 def fetch(self) -> list[Listing]: 53 def fetch(self) -> list[Listing]:
54 listings: list[Listing] = [] 54 listings: list[Listing] = []
55− # Hoquets réseau transitoires (vagues DNS du nœud 09-10/09-18, resets 55+ # Hoquets transitoires récurrents : GET en échec (vagues DNS du nœud
56− # du VPS) : retry court, puis échec FRANC — un `return []` silencieux 56+ # 09-10/09-18, resets du VPS) mais AUSSI 200 servi SANS cartes
57− # devenait « 0 trouvé ok » et déclenchait la dérive/stale à tort. 57+ # (épisodes 10-17 et 10-29) — les deux se retryent, puis échec FRANC
58− html = "" 58+ # (jamais de `return []` silencieux → « 0 trouvé ok » à tort).
59+ arts = []
59 last_err: Exception | None = None 60 last_err: Exception | None = None
60 for attempt in range(3): 61 for attempt in range(3):
62+ if attempt:
63+ time.sleep(3 * attempt)
61 try: 64 try:
62 html = self.get(LIST_URL).text 65 html = self.get(LIST_URL).text
63− break
64 except Exception as e: # noqa: BLE001 — retry puis erreur franche 66 except Exception as e: # noqa: BLE001 — retry puis erreur franche
65 last_err = e 67 last_err = e
66− if attempt < 2: 68+ continue
67− time.sleep(3 * (attempt + 1)) 69+ soup = BeautifulSoup(html, "html.parser")
70+ arts = soup.select("article.c--article-project")
71+ if arts:
72+ break
73+ last_err = None
68 else: 74 else:
69− raise RuntimeError( 75+ if last_err is not None:
70− f"sotramont : portfolio inaccessible après 3 tentatives " 76+ raise RuntimeError(
71− f"({last_err!r}) — {LIST_URL}") 77+ f"sotramont : portfolio inaccessible après 3 tentatives "
72− soup = BeautifulSoup(html, "html.parser") 78+ f"({last_err!r}) — {LIST_URL}")
73−
74− arts = soup.select("article.c--article-project")
75− if not arts:
76 # Vrai zéro = cartes présentes mais aucune locative active ; 79 # Vrai zéro = cartes présentes mais aucune locative active ;
77− # AUCUNE carte = gabarit remanié ou page vide → erreur franche. 80+ # AUCUNE carte ×3 = gabarit remanié ou page vide → erreur franche.
78 raise RuntimeError( 81 raise RuntimeError(
79− "sotramont : aucune carte projet dans le portfolio — " 82+ "sotramont : aucune carte projet dans le portfolio "
80− f"site remanié ? — {LIST_URL}") 83+ "(3 tentatives) — site remanié ? — "
84+ f"{LIST_URL}")
81 85
82 seen: set[str] = set() 86 seen: set[str] = set()
83 for art in arts: 87 for art in arts:
84 88
Menu

Theme