SPB Git forge

spb/job-ka

Public
229commits 1branches 0releases
38.1 MBsize
maindefault branch
1 h agolast push
HTML 82.1% Python 14.6% TypeScript 1.9% CSS 1% JavaScript 0.5%

[ka6] connecteur shrinerschildrens: maintenance tenant Workday (401 'system account', 2026-09-04 ~02h EDT, portail redirigé vers community.workday.com/maintenance-page) — retry+backoff du 401 de maintenance dans _req_json de la plateforme workday et erreur explicite dans sync_log; autres tenants wd12 non touchés (cabotcorp 4 offres vérifié)

Simon-Pierre Boucher committed 20 days ago (Sep 4, 2026) parent a2c6823

1 changed file +38 −8

modified jobka/connectors/workday.py +38 −8
@@ -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,6 +30,8 @@ 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
@@ -55,20 +57,48 @@ class WorkdayConnector(BaseConnector):
55 57 def _base(self) -> str:
56 58 return f"https://{self.TENANT}.{self.HOST}.myworkdayjobs.com"
57 59
60 + @staticmethod
61 + def _is_maintenance_401(exc: requests.exceptions.HTTPError) -> bool:
62 + """401 « Unable to verify credentials for system account » : signature
63 + d'un tenant en maintenance Workday (le portail carrières redirige alors
64 + vers community.workday.com/maintenance-page). Constaté le 2026-09-04
65 + sur shrinerschildrens.wd12 — les autres tenants du même host restaient
66 + servis normalement."""
67 + resp = exc.response
68 + if resp is None or resp.status_code != 401:
69 + return False
70 + try:
71 + return "system account" in resp.text.lower()
72 + except Exception:
73 + return False
74 +
58 75 def _req_json(self, method: str, url: str, **kwargs) -> dict:
59 − # Workday renvoie parfois 200 avec un corps vide/HTML (fenêtres de
60 − # maintenance nocturnes ~03 h EDT, constatées les 29 et 31 août 2026
61 − # sur de nombreux tenants) : on retente avec backoff avant
62 − # d'abandonner, et l'erreur finale nomme le statut HTTP +
63 − # content-type pour que sync_log soit diagnostiquable.
64 − last: ValueError | None = None
76 + # Workday renvoie parfois 200 avec un corps vide/HTML, ou 401
77 + # « system account » (fenêtres de maintenance nocturnes ~02-03 h EDT,
78 + # constatées les 29/31 août et 4 sept. 2026) : on retente avec backoff
79 + # avant d'abandonner, et l'erreur finale est explicite pour que
80 + # sync_log soit diagnostiquable.
81 + last: Exception | None = None
82 + maintenance = False
65 83 for attempt in range(3):
66 − resp = (self.post if method == "post" else self.get)(url, **kwargs)
84 + try:
85 + resp = (self.post if method == "post" else self.get)(url,
86 + **kwargs)
87 + except requests.exceptions.HTTPError as exc:
88 + if not self._is_maintenance_401(exc):
89 + raise
90 + last, maintenance = exc, True
91 + time.sleep(10 * (attempt + 1))
92 + continue
67 93 try:
68 94 return resp.json()
69 95 except ValueError as exc:
70 96 last = exc
71 97 time.sleep(10 * (attempt + 1))
98 + if maintenance:
99 + raise RuntimeError(
100 + "Workday : tenant en maintenance (401 system account) après "
101 + f"3 essais — fenêtre temporaire côté Workday : {last}")
72 102 raise RuntimeError(
73 103 f"Workday non-JSON après 3 essais (HTTP {resp.status_code}, "
74 104 f"{resp.headers.get('content-type')}) : {last}")
75 105