[ka6] snapshot pré-mission derumarketcatering
1 changed file +19 −2
modified
jobka/connectors/workday.py
+19 −2
@@ -5,7 +5,7 @@ | ||
| 5 | 5 | # Fichier : jobka/connectors/workday.py |
| 6 | 6 | # Rôle : Classe de plateforme Workday (API JSON publique wday/cxs) — un |
| 7 | 7 | # employeur = une sous-classe de ~10 lignes (TENANT, HOST, SITE) |
| 8 | −# Créé : 2026-08-17 Modifié : 2026-08-31 | |
| 8 | +# Créé : 2026-08-17 Modifié : 2026-09-04 | |
| 9 | 9 | # ============================================================================= |
| 10 | 10 | """Plateforme Workday. |
| 11 | 11 | |
@@ -30,11 +30,18 @@ import os | ||
| 30 | 30 | import re |
| 31 | 31 | import time |
| 32 | 32 | |
| 33 | +import requests | |
| 34 | + | |
| 33 | 35 | from ..schema import JobPosting, clean_html, is_quebec_location |
| 34 | 36 | from .base import BaseConnector |
| 35 | 37 | |
| 36 | 38 | PAGE_SIZE = 20 |
| 37 | 39 | MAX_DETAILS = int(os.environ.get("JOBKA_WORKDAY_DETAIL_LIMIT", "300")) |
| 40 | +# Échecs de pages détail tolérés par sync : une erreur passagère sur UNE page | |
| 41 | +# (504 Gateway Timeout constaté le 2026-09-04 sur walmart, ~1090 offres | |
| 42 | +# perdues pour un seul GET) ne doit pas avorter toute la source ; au-delà du | |
| 43 | +# budget, la panne est réelle et on la remonte dans sync_log. | |
| 44 | +DETAIL_MISS_BUDGET = 8 | |
| 38 | 45 | |
| 39 | 46 | |
| 40 | 47 | class WorkdayConnector(BaseConnector): |
@@ -207,6 +214,7 @@ class WorkdayConnector(BaseConnector): | ||
| 207 | 214 | out: list[JobPosting] = [] |
| 208 | 215 | by_path: dict[str, JobPosting] = {} |
| 209 | 216 | details_used = 0 |
| 217 | + detail_misses = 0 | |
| 210 | 218 | self._server_filtered = False |
| 211 | 219 | self._first_facets: list = [] |
| 212 | 220 | self._qc_facet = None |
@@ -238,7 +246,16 @@ class WorkdayConnector(BaseConnector): | ||
| 238 | 246 | fresh[0] = True |
| 239 | 247 | return self._fetch_detail(p) |
| 240 | 248 | |
| 241 | − d = self.detail(str(eid), key, _fn) | |
| 249 | + # page détail en erreur (5xx passager, coupure, non-JSON) : | |
| 250 | + # repli sur le cache périmé et on continue — l'échec n'étant | |
| 251 | + # pas mis en cache, la page sera re-tentée au prochain cycle | |
| 252 | + try: | |
| 253 | + d = self.detail(str(eid), key, _fn) | |
| 254 | + except (requests.RequestException, RuntimeError): | |
| 255 | + detail_misses += 1 | |
| 256 | + if detail_misses > DETAIL_MISS_BUDGET: | |
| 257 | + raise | |
| 258 | + d = self.stale_detail(str(eid)) | |
| 242 | 259 | if fresh[0]: |
| 243 | 260 | details_used += 1 |
| 244 | 261 | else: |
| 245 | 262 | |