[ka6] fix connecteur jci: 500 transitoire de l'API Workday (jci.wd5, Johnson Controls) — le sync de 05:26 a échoué sur un unique HTTP 500 de POST /wday/cxs/jci/JCI/jobs (endpoint revenu à la normale: rejeu = 3 offres QC actives, médiane historique 3.0, aucune donnée perdue). Cause d'aggravation: _ka_resilient_post (base.py) ne relançait que sur timeout/coupure réseau, donc un seul 5xx passager avortait tout le sync de la source et la marquait stale. Durcissement minimal: relance (3 tentatives, backoff 5s/10s) aussi sur HTTPError >= 500, en direct (chaîne proxy GET-only); 4xx jamais relancés (403/429 anti-bot: rejouer à l'identique ne débloque pas). Testé: simulation 500-500-200 -> succès à la 3e tentative, 404 -> échec immédiat sans relance, 500 persistant -> lève après 3; sync réel jci avec le fix: found=3, 3 actives. pm2 restart job-ka-sync OK, site 200.
1 changed file +14 −6
modified
jobka/connectors/base.py
+14 −6
@@ -5,7 +5,7 @@ | ||
| 5 | 5 | # Fichier : jobka/connectors/base.py |
| 6 | 6 | # Rôle : Classe de base des connecteurs + backends de fetch (requests |
| 7 | 7 | # direct, Scrapfly pour les pages carrières JS / derrière anti-bot) |
| 8 | −# Créé : 2026-08-17 Modifié : 2026-08-26 | |
| 8 | +# Créé : 2026-08-17 Modifié : 2026-08-27 | |
| 9 | 9 | # ============================================================================= |
| 10 | 10 | from __future__ import annotations |
| 11 | 11 | |
@@ -239,17 +239,25 @@ if not getattr(BaseConnector, "_KA_RESILIENT_WRAPPED", False): | ||
| 239 | 239 | _ka_orig_post = BaseConnector.post |
| 240 | 240 | |
| 241 | 241 | def _ka_resilient_post(self, url, **kw): |
| 242 | − """POST avec relances : un timeout/coupure ponctuel (ex. Workday lent | |
| 243 | − sur l'API liste) ne doit pas avorter tout le sync de la source — la | |
| 244 | − chaîne d'escalade proxy est GET-only, on relance donc en direct.""" | |
| 242 | + """POST avec relances : un timeout/coupure ponctuel ou un 5xx passager | |
| 243 | + (ex. Workday lent ou en erreur interne sur l'API liste — vu sur jci le | |
| 244 | + 2026-08-27, 500 unique puis retour à la normale) ne doit pas avorter | |
| 245 | + tout le sync de la source — la chaîne d'escalade proxy est GET-only, | |
| 246 | + on relance donc en direct. Les 4xx (dont 403/429 anti-bot) ne sont pas | |
| 247 | + relancés : rejouer à l'identique ne les débloque pas.""" | |
| 245 | 248 | last_exc = None |
| 246 | 249 | for attempt in range(3): |
| 247 | 250 | try: |
| 248 | 251 | return _ka_orig_post(self, url, **kw) |
| 249 | 252 | except (_ka_requests.ConnectionError, _ka_requests.Timeout) as exc: |
| 250 | 253 | last_exc = exc |
| 251 | − if attempt < 2: | |
| 252 | − time.sleep(5 * (attempt + 1)) | |
| 254 | + except _ka_requests.HTTPError as exc: | |
| 255 | + r = getattr(exc, "response", None) | |
| 256 | + if r is None or r.status_code < 500: | |
| 257 | + raise | |
| 258 | + last_exc = exc | |
| 259 | + if attempt < 2: | |
| 260 | + time.sleep(5 * (attempt + 1)) | |
| 253 | 261 | raise last_exc |
| 254 | 262 | |
| 255 | 263 | BaseConnector.get = _ka_resilient_get |
| 256 | 264 | |