[ka2] fix connecteur c21_on: retry avec backoff dans _query (une réponse 200 non-JSONP transitoire — throttle Moxi/escalade Oxylabs — avortait tout le fetch ~45 min de l'Ontario)
1 changed file +22 −6
modified
immoka/connectors/c21_canada.py
+22 −6
@@ -24,6 +24,8 @@ import json | |||||
| 24 | import re | 24 | import re | ||
| 25 | import time | 25 | import time | ||
| 26 | 26 | ||||
| 27 | +import requests | ||||
| 28 | + | ||||
| 27 | from .base import BaseConnector | 29 | from .base import BaseConnector | ||
| 28 | from ..schema import PropertyListing | 30 | from ..schema import PropertyListing | ||
| 29 | 31 | ||||
@@ -89,12 +91,26 @@ class _C21Province(BaseConnector): | |||||
| 89 | params["pricemin"] = str(pricemin) | 91 | params["pricemin"] = str(pricemin) | ||
| 90 | if pricemax is not None: | 92 | if pricemax is not None: | ||
| 91 | params["pricemax"] = str(pricemax) | 93 | params["pricemax"] = str(pricemax) | ||
| 92 | − resp = self.get(API, params=params) | 94 | + # Un fetch provincial = des centaines de requêtes sur ~45 min (Ontario) : | ||
| 93 | − body = _CB_RE.sub("", resp.text.strip()) | 95 | + # Moxi throttle parfois, ou l'escalade anti-bot renvoie un 200 au corps | ||
| 94 | − d = json.loads(body) | 96 | + # non-JSONP. Sans retry, UNE réponse pourrie avortait tout le sync | ||
| 95 | − if d.get("status") != "success": | 97 | + # (cause du stale c21_on 2026-08-29/30) → on retente avec backoff. | ||
| 96 | − raise RuntimeError(f"c21 API: {d.get('message', d.get('status'))}") | 98 | + last_exc: Exception | None = None | ||
| 97 | − return d["data"] | 99 | + for attempt in range(4): | ||
| 100 | + if attempt: | ||||
| 101 | + time.sleep(min(5.0 * 2 ** (attempt - 1), 20.0)) | ||||
| 102 | + try: | ||||
| 103 | + resp = self.get(API, params=params) | ||||
| 104 | + body = _CB_RE.sub("", resp.text.strip()) | ||||
| 105 | + d = json.loads(body) | ||||
| 106 | + if d.get("status") != "success": | ||||
| 107 | + raise RuntimeError( | ||||
| 108 | + f"c21 API: {d.get('message', d.get('status'))}") | ||||
| 109 | + return d["data"] | ||||
| 110 | + except (json.JSONDecodeError, RuntimeError, | ||||
| 111 | + requests.RequestException) as exc: | ||||
| 112 | + last_exc = exc | ||||
| 113 | + raise last_exc # type: ignore[misc] | ||||
| 98 | 114 | ||||
| 99 | def _count(self, lo: int | None, hi: int | None, | 115 | def _count(self, lo: int | None, hi: int | None, | ||
| 100 | location: str | None = None) -> int: | 116 | location: str | None = None) -> int: | ||
| 101 | 117 | ||||