Skip to content

Commit 3d591a6

Browse files
committed
improvement against API failure 502 (2 allowed loops)
1 parent 0e101ec commit 3d591a6

2 files changed

Lines changed: 66 additions & 15 deletions

File tree

‎tools/tx_activity.py‎

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import ssl
3434
import subprocess
3535
import sys
36+
import time
3637
import urllib.error
3738
import urllib.parse
3839
import urllib.request
@@ -41,6 +42,9 @@
4142

4243
API = "https://rest.api.transifex.com"
4344

45+
# Wie oft ein voruebergehender Serverfehler wiederholt wird.
46+
VERSUCHE = 4
47+
4448
# Am 2026-10-03 gegen python-newest geprueft: das Attribut heisst
4549
# datetime_translated, der zugehoerige Filter date_translated.
4650
DATUMSFILTER = [
@@ -112,18 +116,27 @@ def ressourcen(wurzel: Path) -> tuple:
112116
return karte, org, projekt
113117

114118

115-
def seiten(pfad: str, params: dict, tok: str):
116-
"""Alle Seiten einer JSON:API-Sammlung durchlaufen."""
117-
url = API + pfad + ("?" + urllib.parse.urlencode(params) if params else "")
118-
while url:
119+
def hole(url: str, tok: str) -> dict:
120+
"""Eine Seite abrufen -- mit Wiederholung bei voruebergehenden Fehlern.
121+
122+
Transifex liefert sporadisch ein 502. Frueher wurde die Ressource dann
123+
stillschweigend uebersprungen und fehlte im Bericht.
124+
"""
125+
for versuch in range(1, VERSUCHE + 1):
119126
req = urllib.request.Request(url, headers={
120-
"Authorization": "Bearer " + tok,
127+
"Authorization": f"Bearer {tok}",
121128
"Accept": "application/vnd.api+json",
122129
})
123130
try:
124131
with urllib.request.urlopen(req, timeout=90, context=KONTEXT) as antwort:
125-
daten = json.load(antwort)
132+
return json.load(antwort)
126133
except urllib.error.HTTPError as e:
134+
if (e.code >= 500 or e.code == 429) and versuch < VERSUCHE:
135+
warte = 2 ** versuch
136+
print(f" HTTP {e.code}, neuer Versuch in {warte}s "
137+
f"({versuch}/{VERSUCHE - 1})", file=sys.stderr)
138+
time.sleep(warte)
139+
continue
127140
rumpf = e.read().decode("utf-8", "replace")[:400]
128141
raise RuntimeError(f"HTTP {e.code} bei {url}\n{rumpf}") from None
129142
except urllib.error.URLError as e:
@@ -133,7 +146,20 @@ def seiten(pfad: str, params: dict, tok: str):
133146
' open "/Applications/Python 3.14/Install Certificates.command"\n'
134147
"oder im aktiven venv: pip install certifi"
135148
)
149+
if versuch < VERSUCHE:
150+
warte = 2 ** versuch
151+
print(f" Netzwerkfehler, neuer Versuch in {warte}s", file=sys.stderr)
152+
time.sleep(warte)
153+
continue
136154
raise RuntimeError(f"Netzwerkfehler bei {url}: {e.reason}") from None
155+
raise RuntimeError(f"Nach {VERSUCHE} Versuchen aufgegeben: {url}")
156+
157+
158+
def seiten(pfad: str, params: dict, tok: str):
159+
"""Alle Seiten einer JSON:API-Sammlung durchlaufen."""
160+
url = API + pfad + ("?" + urllib.parse.urlencode(params) if params else "")
161+
while url:
162+
daten = hole(url, tok)
137163
for eintrag in daten.get("data", []):
138164
yield eintrag
139165
url = (daten.get("links") or {}).get("next")

‎tools/tx_diff.py‎

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@
2525
import ssl
2626
import subprocess
2727
import sys
28+
import time
2829
import urllib.error
2930
import urllib.parse
3031
import urllib.request
3132
from datetime import datetime, timedelta, timezone
3233
from pathlib import Path
3334

3435
API = "https://rest.api.transifex.com"
36+
37+
# Wie oft ein voruebergehender Serverfehler wiederholt wird.
38+
VERSUCHE = 4
3539
KUERZUNG = 160
3640

3741

@@ -91,28 +95,49 @@ def ressourcen(wurzel: Path) -> tuple:
9195
return karte, org, projekt
9296

9397

94-
def seiten(pfad: str, params: dict, tok: str):
95-
"""Liefert (data-Eintrag, included-Karte) fuer alle Seiten."""
96-
url = API + pfad + ("?" + urllib.parse.urlencode(params) if params else "")
97-
while url:
98+
def hole(url: str, tok: str) -> dict:
99+
"""Eine Seite abrufen -- mit Wiederholung bei voruebergehenden Fehlern.
100+
101+
Transifex liefert sporadisch ein 502. Frueher wurde die Ressource dann
102+
stillschweigend uebersprungen und fehlte im Bericht.
103+
"""
104+
for versuch in range(1, VERSUCHE + 1):
98105
req = urllib.request.Request(url, headers={
99-
"Authorization": "Bearer " + tok,
106+
"Authorization": f"Bearer {tok}",
100107
"Accept": "application/vnd.api+json",
101108
})
102109
try:
103110
with urllib.request.urlopen(req, timeout=90, context=KONTEXT) as antwort:
104-
daten = json.load(antwort)
111+
return json.load(antwort)
105112
except urllib.error.HTTPError as e:
113+
if (e.code >= 500 or e.code == 429) and versuch < VERSUCHE:
114+
warte = 2 ** versuch
115+
print(f" HTTP {e.code}, neuer Versuch in {warte}s "
116+
f"({versuch}/{VERSUCHE - 1})", file=sys.stderr)
117+
time.sleep(warte)
118+
continue
106119
rumpf = e.read().decode("utf-8", "replace")[:300]
107120
raise RuntimeError(f"HTTP {e.code}: {rumpf}") from None
108121
except urllib.error.URLError as e:
109122
if "CERTIFICATE_VERIFY_FAILED" in str(e.reason):
110123
sys.exit('Wurzelzertifikate fehlen -- "Install Certificates.command" '
111124
"ausfuehren oder certifi installieren.")
112-
raise RuntimeError(f"Netzwerkfehler: {e.reason}") from None
113-
beigefuegt = {e["id"]: e for e in daten.get("included", [])}
125+
if versuch < VERSUCHE:
126+
warte = 2 ** versuch
127+
print(f" Netzwerkfehler, neuer Versuch in {warte}s", file=sys.stderr)
128+
time.sleep(warte)
129+
continue
130+
raise RuntimeError(f"Netzwerkfehler bei {url}: {e.reason}") from None
131+
raise RuntimeError(f"Nach {VERSUCHE} Versuchen aufgegeben: {url}")
132+
133+
134+
def seiten(pfad: str, params: dict, tok: str):
135+
"""Alle Seiten einer JSON:API-Sammlung durchlaufen."""
136+
url = API + pfad + ("?" + urllib.parse.urlencode(params) if params else "")
137+
while url:
138+
daten = hole(url, tok)
114139
for eintrag in daten.get("data", []):
115-
yield eintrag, beigefuegt
140+
yield eintrag
116141
url = (daten.get("links") or {}).get("next")
117142

118143

0 commit comments

Comments
 (0)