SPB Git

spb/lou-ka

Public

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

[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

Simon-Pierre Boucher committed (Aug 27, 2026) parent b2d36fa Browse files

1 changed file +16 −9

Unified Split
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
Menu

Theme