[ka2] fix connecteur realstar: retry (3 essais, backoff 5/10 s) sur 5xx Firecrawl dans _rendered — un 502 transitoire (vu 2026-08-21 et 2026-08-27) ne fait plus tomber tout le sync
1 changed file +16 −9
modified
louka/connectors/realstar.py
+16 −9
@@ -25,6 +25,7 @@ from __future__ import annotations | |||||
| 25 | import hashlib | 25 | import hashlib | ||
| 26 | import os | 26 | import os | ||
| 27 | import re | 27 | import re | ||
| 28 | +import time | ||||
| 28 | 29 | ||||
| 29 | from bs4 import BeautifulSoup | 30 | from bs4 import BeautifulSoup | ||
| 30 | 31 | ||||
@@ -104,15 +105,21 @@ class RealstarConnector(BaseConnector): | |||||
| 104 | # Clé absente : on tente quand même (le rejeu des fixtures intercepte | 105 | # Clé absente : on tente quand même (le rejeu des fixtures intercepte | ||
| 105 | # self.session ; en direct, Firecrawl répondra 401 -> erreur claire). | 106 | # self.session ; en direct, Firecrawl répondra 401 -> erreur claire). | ||
| 106 | key = os.environ.get("FIRECRAWL_API_KEY", "") | 107 | key = os.environ.get("FIRECRAWL_API_KEY", "") | ||
| 107 | − # via self.session : l'enregistreur de fixtures capture la réponse | 108 | + # Firecrawl renvoie parfois un 502 transitoire (2026-08-21 et | ||
| 108 | − resp = self.session.post( | 109 | + # 2026-08-27) : un retry court évite de faire tomber tout le sync. | ||
| 109 | − FIRECRAWL_API, | 110 | + for attempt in range(3): | ||
| 110 | − json={"url": url, "formats": ["html"], "waitFor": wait_ms}, | 111 | + # via self.session : l'enregistreur de fixtures capture la réponse | ||
| 111 | − headers={"Authorization": f"Bearer {key}"}, | 112 | + resp = self.session.post( | ||
| 112 | − timeout=150, | 113 | + FIRECRAWL_API, | ||
| 113 | − ) | 114 | + json={"url": url, "formats": ["html"], "waitFor": wait_ms}, | ||
| 114 | − resp.raise_for_status() | 115 | + headers={"Authorization": f"Bearer {key}"}, | ||
| 115 | − return (resp.json().get("data") or {}).get("html", "") | 116 | + timeout=150, | ||
| 117 | + ) | ||||
| 118 | + if resp.status_code >= 500 and attempt < 2: | ||||
| 119 | + time.sleep(5 * (attempt + 1)) | ||||
| 120 | + continue | ||||
| 121 | + resp.raise_for_status() | ||||
| 122 | + return (resp.json().get("data") or {}).get("html", "") | ||||
| 116 | 123 | ||||
| 117 | def fetch(self) -> list[Listing]: | 124 | def fetch(self) -> list[Listing]: | ||
| 118 | self._renders = 0 | 125 | self._renders = 0 | ||
| 119 | 126 | ||||