Fejl 503 og timeouts
Forstå hvilke endpoints der afhænger af offentlige registre i realtid, håndter 503 upstream_unavailable med Retry-After, og sæt fornuftige timeouts i klienten.
De fleste kald bliver besvaret fra vores egen database, også når de offentlige registre er nede. Nogle berigelser henter data live fra Datafordeleren og andre offentlige kilder, og de kan svare 503, når kilden ikke svarer. Denne guide viser hvilke, hvad svaret indeholder, og hvordan du indstiller timeouts og genforsøg.
Hvad afhænger af hvad
| Endpoint | Datakilde ved kaldet | Kan give 503 |
|---|---|---|
Alle DAWA-stier (/autocomplete, /adresser, /datavask/…, /postnumre, /replikering/… osv.) | Vores database | Nej |
/api/v1/datavask/parse, /api/v1/enrich/distance, /api/v1/enrich/validate/… | Vores database / lokal beregning | Nej |
/api/v1/enrich/adresser/{id}/dagi, /bbr, /enhed, /virksomheder | Vores database | Nej |
/api/v1/enrich/adresser/{id}/ejendom, /property, /installations | Datafordeleren live, gemt i 24 timer pr. adresse | Ja, upstream_unavailable og upstream_busy |
/api/v1/enrich/adresser/{id}/climate | DHM og DMI Klimaatlas live, gemt i 24 timer | Kun upstream_busy. Ellers markeres de dele, der mangler, i svaret |
/api/v1/enrich/adresser/{id}/all | Alle ovenstående på én gang | Nej. Dele, der fejler, er null |
Adressedata bliver opdateret fra Datafordeleren i baggrunden. Er Datafordeleren nede, får du stadig svar, men ændringer fra de seneste timer kan mangle, indtil synkroniseringen er tilbage.
upstream_unavailable
Datafordeleren har planlagte servicevinduer og af og til nedbrud. I et servicevindue afviser den alle nøgler, og så kan vi ikke hente data, der ikke allerede ligger i vores cache. Svaret er:
HTTP/2 503 retry-after: 60 cache-control: no-store content-type: application/json
{
"error": {
"code": "upstream_unavailable",
"message": "An upstream data register is temporarily unavailable. Retry in a minute.",
"details": null
}
}Det samme svar kommer, hvis Datafordeleren ikke svarer inden for vores egen timeout.
Hvad du gør:
- Prøv igen efter det antal sekunder,
Retry-Afterangiver. Browserkode kan også læse headeren, fordi API'et giver adgang til den via CORS. Et servicevindue kan vare fra minutter til timer, så lad ventetiden vokse efter et par forsøg. - Vis brugeren adressen uden berigelsen, og hent den senere. Adressedata er stadig tilgængelige.
- Har du hentet berigelsen for den samme adresse inden for de sidste 24 timer, kommer den fra cache og virker også under nedbruddet.
- Se driftsstatus på /status.
upstream_busy
{
"error": {
"code": "upstream_busy",
"message": "Enrichment is briefly rate-limited to protect the upstream register. Retry in a moment.",
"details": null
}
}Alle kunder deler én nøgle til de offentlige registre. Kommer der mange berigelseskald for adresser, der ikke ligger i cache, på samme tid, holder vi kortvarigt igen. Svaret er 503 med Retry-After: 2. Vent to sekunder og prøv igen. Skal du berige mange adresser, så gør det i et jævnt tempo i stedet for i store parallelle bølger.
502 og 504 fra proxyen
En 502 eller 504 uden JSON-body kommer fra proxyen foran API'et: en timeout på en langsom forespørgsel eller et kort øjeblik under en udrulning. Body er en HTML-side, så din fejlhåndtering må ikke antage JSON. Behandl dem som 503 uden Retry-After: vent et par sekunder og prøv igen. En fejl fra selve API'et, også en 500, har altid en JSON-body med en code.
Timeouts i din klient
Uden timeout kan en hængende forbindelse blokere en tråd eller en worker i lang tid. Sæt altid både en forbindelses-timeout og en læse-timeout:
| Kald | Læse-timeout |
|---|---|
/autocomplete i et inputfelt | 3-5 sekunder. Brugeren skriver videre, og det næste kald erstatter det gamle |
| Adresseopslag, datavask, lister | 10-15 sekunder |
ejendom, property, installations, all første gang for en adresse | 60 sekunder. Kaldet slår op i flere registre efter hinanden |
/replikering/udtraek | Ingen samlet timeout. Brug en læse-timeout pr. blok, fordi svaret strømmer |
Et eksempel med httpx, der har separate timeouts for forbindelse og læsning:
import os import httpx timeout = httpx.Timeout(connect=5.0, read=15.0, write=10.0, pool=5.0) with httpx.Client( base_url="https://api.danadresse.dk", headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]}, timeout=timeout, ) as client: r = client.get("/postnumre/8000") r.raise_for_status() print(r.json()["navn"])
Genforsøg for berigelser
Funktionen her henter en berigelse og prøver igen ved 502, 503 og 504 og ved timeouts. Den bruger Retry-After, når headeren findes, og ellers en voksende ventetid. 4xx-fejl bliver ikke prøvet igen, fordi de ikke går væk af sig selv. Berigelser kræver en live-nøgle:
import os import random import time import httpx API = "https://api.danadresse.dk" RETRY_STATUS = {502, 503, 504} client = httpx.Client( base_url=API, headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]}, timeout=httpx.Timeout(connect=5.0, read=60.0, write=10.0, pool=5.0), ) def enrich(adgangsadresse_id: str, kind: str = "ejendom", attempts: int = 5) -> dict | None: """Hent /api/v1/enrich/adresser/{id}/{kind}. None, hvis kilden stadig er nede.""" for attempt in range(attempts): try: r = client.get(f"/api/v1/enrich/adresser/{adgangsadresse_id}/{kind}") except (httpx.TimeoutException, httpx.TransportError): r = None if r is not None and r.status_code not in RETRY_STATUS: r.raise_for_status() # 4xx: ret kaldet, prøv ikke igen return r.json() retry_after = r.headers.get("Retry-After", "") if r is not None else "" wait = int(retry_after) if retry_after.isdigit() else min(60, 2 ** attempt) time.sleep(wait + random.random()) return None if __name__ == "__main__": data = enrich("0a3f507c-0624-32b8-e044-0003ba298018") print("Ingen data lige nu" if data is None else sorted(data))
Til lange batchjobs er det bedre at lægge adresser, der fejler, i en kø og prøve dem igen senere end at vente i løkken. Se Retries og backoff i produktion.
Næste skridt
Relaterede guides
Markdown-kilde Fejl i guiden? Skriv til os API-reference (Swagger)