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.

4 min Niveau: Øvet ✓ Kode testet

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

EndpointDatakilde ved kaldetKan give 503
Alle DAWA-stier (/autocomplete, /adresser, /datavask/…, /postnumre, /replikering/… osv.)Vores databaseNej
/api/v1/datavask/parse, /api/v1/enrich/distance, /api/v1/enrich/validate/…Vores database / lokal beregningNej
/api/v1/enrich/adresser/{id}/dagi, /bbr, /enhed, /virksomhederVores databaseNej
/api/v1/enrich/adresser/{id}/ejendom, /property, /installationsDatafordeleren live, gemt i 24 timer pr. adresseJa, upstream_unavailable og upstream_busy
/api/v1/enrich/adresser/{id}/climateDHM og DMI Klimaatlas live, gemt i 24 timerKun upstream_busy. Ellers markeres de dele, der mangler, i svaret
/api/v1/enrich/adresser/{id}/allAlle ovenstående på én gangNej. 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#upstream-headers
HTTP/2 503
retry-after: 60
cache-control: no-store
content-type: application/json
JSON#upstream-body
{
  "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-After angiver. 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

JSON#busy-body
{
  "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:

KaldLæse-timeout
/autocomplete i et inputfelt3-5 sekunder. Brugeren skriver videre, og det næste kald erstatter det gamle
Adresseopslag, datavask, lister10-15 sekunder
ejendom, property, installations, all første gang for en adresse60 sekunder. Kaldet slår op i flere registre efter hinanden
/replikering/udtraekIngen 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:

Python#httpx-timeouts
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:

Python#enrich-retry
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)

Prøv det med en gratis nøgle

2 000 kald/måned på gratisplanen. Intet kreditkort.

Opret konto →