[ka2] fix connecteur lienard: erreur franche au lieu d'un « 0 trouvé ok » qui dépublie — lienard.ca est en panne serveur depuis ~2026-09-04 (timeouts puis 500 « Erreur de la base de données » WordPress, confirmé aussi via proxy résidentiel CA : panne côté hébergeur, pas un blocage IP; cert TLS renouvelé 2026-08-20 et Instagram actif → site pas mort, panne temporaire). fetch() avalait les exceptions et retournait [] en silence : 2 syncs du 2026-09-04 ont dépublié les 8 annonces à tort. Désormais retry (3 essais, backoff 5/10 s) des 2 pages plans puis RuntimeError si aucun bloc Image Map Pro (0 unité « Disponible » dans un HTML valide reste légitime). L'inventaire se republiera au retour du site. Testé: run.py sync lienard → échec franc journalisé (ok=0, removed=0), plus de dépublication silencieuse
1 changed file +26 −7
modified
louka/connectors/lienard.py
+26 −7
@@ -13,6 +13,7 @@ from __future__ import annotations | ||
| 13 | 13 | |
| 14 | 14 | import json |
| 15 | 15 | import re |
| 16 | +import time | |
| 16 | 17 | |
| 17 | 18 | from ..schema import Listing |
| 18 | 19 | from .base import BaseConnector |
@@ -53,16 +54,34 @@ class LienardConnector(BaseConnector): | ||
| 53 | 54 | |
| 54 | 55 | def fetch(self) -> list[Listing]: |
| 55 | 56 | listings: list[Listing] = [] |
| 57 | + # Panne serveur lienard.ca (vue 2026-09-04 : timeouts puis « Erreur | |
| 58 | + # de la base de données » WordPress) : les exceptions étaient avalées | |
| 59 | + # et fetch() retournait [] en silence — le sync concluait « 0 trouvé | |
| 60 | + # ok » et dépubliait l'inventaire. Retry court (3 essais, backoff | |
| 61 | + # 5/10 s) puis erreur franche si aucune page ne livre les blocs | |
| 62 | + # Image Map Pro (0 unité « Disponible » dans un HTML valide reste | |
| 63 | + # un résultat légitime). | |
| 56 | 64 | html = "" |
| 57 | − for page in PAGES: | |
| 58 | − try: | |
| 59 | − html = self.get(page).text | |
| 60 | − except Exception: | |
| 61 | − continue | |
| 62 | − if SETTINGS_RE.search(html): | |
| 65 | + last_exc: Exception | None = None | |
| 66 | + for attempt in range(3): | |
| 67 | + for page in PAGES: | |
| 68 | + try: | |
| 69 | + text = self.get(page).text | |
| 70 | + except Exception as exc: | |
| 71 | + last_exc = exc | |
| 72 | + continue | |
| 73 | + if SETTINGS_RE.search(text): | |
| 74 | + html = text | |
| 75 | + break | |
| 76 | + if html: | |
| 63 | 77 | break |
| 78 | + if attempt < 2: | |
| 79 | + time.sleep(5 * (attempt + 1)) | |
| 64 | 80 | if not html: |
| 65 | − return listings | |
| 81 | + raise RuntimeError( | |
| 82 | + "aucun bloc Image Map Pro sur les pages plans après 3 essais " | |
| 83 | + f"(dernière erreur : {last_exc!r}) — lienard.ca en panne ou " | |
| 84 | + "format changé ?") | |
| 66 | 85 | |
| 67 | 86 | seen: set[str] = set() |
| 68 | 87 | for m in SETTINGS_RE.finditer(html): |
| 69 | 88 | |