Net-Base Magasin

08.08.2026

RESTClient i Delphi: Robust mot tidsavbrudd, gjenforsøk og 429-ratebegrensninger med backoff

Når REST-anrop i Delphi sporadisk henger, utløser timeouts eller kommer tilbake med 429 Rate-Limits, er det ikke nok å "bare sende på nytt". Denne praksisartikkelen viser hvordan du med RESTClient oppnår kontrollerte timeouts, sikre retries, backoff med jitter og ryddig logging...

08.08.2026

Fra magasinetema til prosjektpraksis

Egnede tjeneste- og tekniske sider for innlegget

Et REST-kall er i teorien enkelt: forespørsel ut, respons inn, ferdig. I praksis feiler produktive integrasjoner sjelden på «feil URL», men på randtilfeller i drift: sporadiske Timeouts, kortvarige DNS- eller TLS-problemer, overbelastede downstream-systemer, eller 429 (Too Many Requests), fordi et API-Gateway demper trafikken. Nettopp her skiller en demo-prototype seg fra en langsiktig driftbar integrasjon.

Denne artikkelen viser hvordan du med RESTClient i Delphi etablerer robuste kommunikasjonsveier: klare Timeout-definisjoner, målrettede gjenforsøk bare der de er faglig og teknisk trygge, og en backoff-atferd som respekterer ratebegrensninger i stedet for å forverre dem. Fokus er ikke på «pen kode», men på oppførsel under last, evne til debugging, klar feilklassifisering og vurderingen av når den ekstra innsatsen faktisk lønner seg.

Hvorfor Timeouts, Gjenforsøk og 429 i reelle miljøer forekommer sammen

I bedriftsnettverk går REST-kall sjelden «direkte ut på Internett». Typisk finnes proxy-kjeder, TLS-terminering, API-Gateways, WAFs (Web Application Firewall) og flere interne hopp. Hvert ledd kan ha egne Timeouts og begrensninger. Et Timeout på klienten kan bety:

  • Serveren har ikke svart (overbelastning, deadlock, downstream henger).
  • Responsen kom, men for sent (dårlig rute, pakketap, kø/overbelastning).
  • Du har låst deg ute selv: for korte Timeouts eller en blokkert UI-/hovedtråd.

Parallelt fører «naive» gjenforsøk ofte til flere problemer: Hvis en server allerede er ved sin grense, øker gjenforsøk lasten og gjør en liten flaskehals til en alvorlig feil. Ved 429 er dette enda tydeligere: Et rate-limit er en eksplisitt oppfordring om å sende mindre eller komme tilbake senere. En klient uten backoff oppfører seg som en DoS-generator, om enn utilsiktet.

Robusthet oppnås derfor ikke gjennom «gjenforsøk overalt», men gjennom en konsistent beslutningsmodell: Hvilke feil er transiente (midlertidige), hvilke er permanente, hvilke forespørsler er gjenforsøkbare (idempotente), og hvordan styrer du ventetidene slik at systemet ditt forblir stabilt.

Timeouts korrekt sette: Hva betyr egentlig «Timeout» for RESTClient i Delphi?

En vanlig fallgruve: «Timeout» er ikke alltid det samme som Timeout. Avhengig av stack finnes det ulike faser. Selv om Delphi-REST-komponenter kapsler mye, bør du ha modellen i hodet:

  • Connect-Timeout: tid til TCP-forbindelsen er etablert (inkludert DNS/TLS avhengig av implementasjon).
  • Read/Response-Timeout: tid til bytes kommer fra serveren eller til svaret er fullstendig.
  • Gesamt-Timeout: øvre grense for hele kallet inkludert gjenforsøk.

I praksis er en for kort Timeout minst like farlig som en for lang: Du skaper kunstige feil som så gjenforsøkes og dermed genererer belastning. Omvendt blokkerer en for lang Timeout worker-tråder, køplasser eller UI-respons. For drift og administrasjon er det viktig at Timeouts er konfigurerbare (for eksempel per endepunkt) og at de logges.

Anbefaling fra praksis: To nivåer i stedet for ett tall

For REST-kall i forretningsprogramvare har to nivåer vist seg å fungere:

  • Call-Timeout (per forespørsel): en realistisk øvre grense som passer til brukstilfellet.
  • Job-Timeout (overordnet): hvis du har en batch-behandling eller en sync-jobb, begrens total kjøretid og avbryt ryddig.

Slik forhindrer du at et enkelt API-svar venter i det uendelige, samtidig som en nattlig jobb ikke kjører «til lunsj» på grunn av mange gjenforsøk.

Gjenforsøk: beslutningen bør være faglig, ikke bare teknisk

Om et gjenforsøk er tillatt er ikke kun et rent teknisk spørsmål. Kjernebegrepet er idempotens: En forespørsel er idempotent når den, ved å bli utført flere ganger, har samme effekt som én gang. Typiske eksempler: GET er idempotent, PUT ofte også (hvis du setter målobjektet fullt ut), DELETE vanligvis også. POST er ofte ikke idempotent (f.eks. «opprette en ny ordre»).

Hvorfor er dette avgjørende? En timeout kan bety at serveren likevel behandlet forespørselen, men svaret nådde ikke klienten. Hvis du da blint gjentar en POST, skaper du duplikater. Det er i drift en klassisk «spøkelsesfeil»: I applikasjonen står det «Timeout», i backend finnes doble poster.

Den sikre basis: gjenforsøk kun for klart retrybare operasjoner

En robust regel som har vist seg i integrasjoner:

  • GET: retrybar ved transiente feil.
  • PUT/DELETE: retrybar hvis API-en din er faglig klart definert (f.eks. ressurs-ID er stabil) og serveren har en korrekt idempotent implementasjon.
  • POST: kun retrybar hvis du har en Idempotency-Key-strategi (faglig entydig forespørsels-ID som server-side forhindrer duplikater) eller hvis POSTen er semantisk idempotent (sjelden, men mulig).

Hvis du ikke kontrollerer API-en, er dette punktet hvor du som teknisk leder må ta en beslutning: Enten godtar du «ingen gjenforsøk ved POST» (og bygger bedre feilmeldinger/resync-mekanismer), eller du forhandler med API-leverandøren om en Idempotency-Key eller en dedupliserbar modell.

429 Too Many Requests: respekter ratebegrensninger i stedet for å «bare retry»

Grafik eines API-Gateways mit gedrosselten Requests und Backoff-Abständen
Ved 429 hjelper kontrollert Backoff: færre samtidige gjenforsøk, jevnere gjenoppretting.

HTTP 429 er ikke en «plagsom feilmelding», men en styringsmekanisme. I bedriftsmiljøer kommer 429 ofte fra:

  • API-Gateway med Token-Bucket/Leaky-Bucket-Limits (ratebegrensning).
  • Cloud-APIer med leietakerbegrensninger per minutt/time.
  • Interne tjenester som beskytter seg mot lasttopper.

For klienten betyr dette: gjenforsøk ja, men kontrollert. To ting er viktige:

  • Tolk Retry-After-headeren hvis den finnes (sekunder eller HTTP-dato).
  • Bruk Backoff når ingen Retry-After kommer, eller hvis du i tillegg tilfører jitter.

Den vanligste fallgruven: 429 behandles som 500 («serverfeil, retry umiddelbart»). Det forsterker strupingen. Bedre er: 429 er et signal om å vente aktivt og eventuelt redusere parallelliteten.

Backoff med Jitter: hvorfor uten tilfeldighet alt kollapser synkront

Exponential Backoff betyr at du øker ventetiden etter hvert feilforsøk (f.eks. 200 ms, 400 ms, 800 ms …). Jitter er en tilfeldig komponent som hindrer at mange klienter banker på samtidig. Uten Jitter skjer i praksis ofte følgende: En ratebegrensning slår inn, 50 klienter får 429, alle venter nøyaktig 1 sekund og sender så samtidig igjen. Resultat: 429 igjen, og du får et „Thundering Herd“-problem.

En praktisk tilnærming er «Full Jitter» eller «Equal Jitter»: Du beregner et backoff-vindu og velger deretter en tilfeldig ventetid innenfor dette vinduet. Det høres ut som en detalj, men i drift gjør det forskjellen mellom stabil gjenoppretting og vedvarende belastning.

Et rent mønster: REST-kall kapsles inn, i stedet for å spre retry-løkker overalt

Hvis du implementerer retries/backoff «ad hoc» ved hvert kallsted, oppstår raskt inkonsekvent oppførsel: ett endepunkt prøver aggressivt igjen, et annet ikke i det hele tatt, logging blir ufullstendig, og administratorene ser bare «sporadiske feil». Det blir robust når du definerer en sentralisert anropsvei:

  • En wrapper rundt RESTClient/RESTRequest som anvender en policy (timeout, retry, backoff).
  • Et enhetlig resultatobjekt: statuskode, varighet, forsøksteller, eventuelt siste Exception.
  • Standardisert logging (Request-ID/Correlation-ID, endepunkt, HTTP-metode, relevante headere).

Det er her ekstra kode virkelig lønner seg: Du får reproducerbar oppførsel, bedre logger, og du kan konfigurere policies per målsystem uten å bygge om applikasjonen.

Policy-beslutningsmatrise (kort og praktisk)

For de fleste integrasjoner er en enkel matrise tilstrekkelig, som du implementerer i wrapperen:

  • Retry ved: nettverksfeil/tilkoblingsbrudd, 408, 429, 502, 503, 504 (avhengig av API-avtale).
  • Ingen retry ved: 400/401/403/404 (som regel konfigurasjon/autentisering/request-feil), 409/422 (faglige konflikter/validering), samt ved POST uten idempotency-key.
  • Maks. forsøk: hold lavt (ofte 2–4 forsøk er nok), sats heller på bedre overvåkning.
  • Maks. backoff: begrens (f.eks. noen sekunder opp til ett minutt), ellers blokkerer du for mange workere.

Viktig: Disse reglene er ikke universelle. 404 kan ved «eventual consistency» være transients, 409 kan ved låsestrategier være transient. Forskjellen er: Da er det en bevisst avvik, ikke tilfeldig oppførsel.

Konkrett kasus: Timeout etter POST – ble det lagret eller ikke?

Papirdiagrammer og notater som visualiserer uklar POST-status etter timeout
Timeout etter POST er farlig: uten idempotens forblir status faglig uklar.

Dette er klassikeren som sjelden lar seg reprodusere rent i debuggere: Du sender en POST (f.eks. «Ticket anlegen»), klienten din får en read-timeout, og brukeren klikker «nochmal». I backend finnes ticketen allerede. Uten mottiltak oppstår duplikater eller inkonsistenser.

Robust blir dette bare med én av tre strategier:

  • Idempotency-Key: Du genererer for hver faglige operasjon en entydig Request-ID (f.eks. GUID), sender den som header, og serveren garanterer deduplisert behandling.
  • Klient-side deduplisering: Du lagrer «pågående forespørsler» lokalt med egen ID og gjør etter timeout en status-sjekk (f.eks. GET etter faglig nøkkel). Dette er merarbeid og ikke alltid mulig.
  • Ingen Retry: Du rapporterer tydelig at status er ukjent, og bygger en manuell/automatisk resync-prosess (f.eks. senere avstemming).

Når du bygger integrasjoner for drift, er «Status unbekannt» en gyldig kategori. Forsøk ikke å kode bort usikkerhet. Logg den, gjør den synlig, og sørg for en avstemmingsvei.

Backoff-design i praksis: grenseverdier, parallellitet og avbryt

Et backoff er ikke bare «Sleep». Du må sette det i kontekst av applikasjonen din:

  • Parallellitet: Hvis du har 20 tråder og alle venter, er 20 tråder blokkert. For tjenester er det ofte greit, for desktop-apper ofte ikke.
  • Avbryt: En bruker avbryter, tjenesten stopper, et jobb avsluttes. Backoff-venting må kunne avbrytes, ellers henger stopp-/shutdown-prosesser.
  • Fairness: Flere endepunkter bør ikke sultes ut av hverandre. Rate-begrensninger er ofte per token eller per endepunkt; din wrapper bør kunne styre per målsystem.

En ryddig tilnærming er: Backoff i en funksjon som venter i korte intervaller og samtidig sjekker et cancel-flag (f.eks. Event/Token). Dette er ingen luksus: Nettopp dette punktet avgjør om en Windows- og Linux-Services stopper ryddig eller henger i Service Control Manager-konsollen.

Maksimal varighet og «Budget» per kall

En robust retry-implementering arbeider ikke bare med «max tries», men også med et tidsbudsjett. Eksempel: Du tillater maksimalt 10 sekunder total tid for kallet inklusive retries. Da kan ikke et enkelt forsøk plutselig blokkere i 30 sekunder bare fordi en timeout er feil satt. For administratorer og drift er dette gull verdt, fordi det begrenser latensspisser og stabiliserer køer.

Feilsøking og driftsdiagnose: Uten gode logger er Retrys usynlige feilforsterkere

Arbeidsplassscene med uskarpe logger og skisset kontekst for request-IDer og retries
Med Correlation-ID, attempt-teller og varighet blir retries etterprøvbare i drift.

Gjenforsøk uten logging er farlig, fordi du til slutt bare hører «det tar noen ganger». Hvis du vil bli robust, trenger du logger som ikke bare skriver ut exceptions, men leverer kontekst:

  • Correlation-ID: en request-ID som du genererer per kall og beholder ved hvert gjenforsøk.
  • Forsøksnummer og Forsinkelse (Backoff).
  • HTTP-status og utvalgte headere (særlig Retry-After, RateLimit-Header hvis tilgjengelig).
  • Varighet per forsøk og total tid.
  • Endepunkt (Host + Pfad), men ingen sensitive data i loggen (tokens, personopplysninger).

For tekniske leads er dette også håndtaket for å justere grenseverdier: Du ser om timeouts «alltid ved 3 sekunder» skjer (sannsynligvis for kort) eller om 429 kommer i bølger (parallelliteten er for høy, backoff for svak eller manglende klientsidige rate-limits).

Typiske loggfeller

  • For mye payload: å logge JSON-bodyer komplett virker hjelpsomt, men eksploderer ved filer/vedlegg og skaper personvernproblemer. Bedre: hash/størrelse, Content-Type, og ved behov målrettet debug-logging via feature-flag.
  • Ingen forskjell mellom timeout og avbrudd: et avbrutt kall er ikke en feil i samme forstand som et timeout. Skill dem, ellers jager administratorer spøkelsesfeil.
  • Gjenforsøk skjuler den første årsaken: hvis forsøk 1 har en TLS-feil og forsøk 2 lykkes, vil du likevel vite at det var en TLS-svikt. Det er et tidlig varselsignal.

Klientsidig ratebegrensning: Når du må styre belastningen selv

429 er serverens respons. I mange scenarier gir det likevel mening å dempe på klientsiden før du produserer 429. Det er særlig relevant når du:

  • har batch-jobber (f.eks. datasykronisering om natten) og API-et kun tillater X forespørsler per minutt.
  • bruker flere workere/tråder og skyter ut forespørsler parallelt.
  • har flere prosessinstanser kjørende (f.eks. terminalservere eller flere tjenester).

I praksis betyr det: du implementerer en liten rate-limiter (f.eks. token-bucket) per målsystem eller per API-nøkkel. Det reduserer 429, stabiliserer gjennomstrømning og gjør kjøretider mer forutsigbare. For drift og kapasitetsplanlegging er dette ofte mer verdifullt enn «enda et gjenforsøk».

Viktig: Rate-limiter og backoff utfyller hverandre

Rate-limiteren holder deg i normaldrift under grensen. Backoff er reaksjonen når du likevel får 429 eller midlertidig overbelastning. Den som kun har backoff kjører konstant «inn i veggen» og bremser. Den som kun har rate-limiter reagerer dårlig på overraskende grenser eller delte kvoter (f.eks. når flere systemer bruker samme API-nøkkel).

Sikkerhet og samsvar: Gjenforsøk må ikke skjule autentiseringsproblemer

I bedrifter er autentisering og autorisering ofte den vanligste «feilen» etter utrulling: utløpte tokens, feilkonfigurerte klient-legitimasjoner, manglende proxy-unntak. Gjenforsøk hjelper ikke her og kan til og med være skadelig, fordi de fyller loggfiler og kan trigge sperremekanismer (f.eks. konto-låsninger, rate-limits på auth-endepunkter).

Praktisk regel: 401/403 må aldri gjenforsøkes (med mindre du har en bevisst token-refresh-håndtering). Hvis du implementerer token-refresh, skill det klart fra retry-mekanismen: forny tokenet først, så send én gang på nytt. Og logg eksplisitt at en refresh fant sted.

Når innsatsen lønner seg – og når ikke

Robuste gjenforsøk og backoff er ikke et mål i seg selv. De lønner seg spesielt når minst ett av disse punktene gjelder:

  • Integrasjonen er forretningskritisk (f.eks. ordreopptak, forsendelse, fakturering).
  • API-en er ekstern eller kun drevet som „best effort“ internt, og du har ikke full kontroll.
  • Du har belastningstopper (f.eks. jobbvindu, månedsavslutning) og vil komme stabilt gjennom.
  • Du kjører det som en Service/Daemon og må kunne stoppes planmessig og på en ryddig måte.

Det lønner seg mindre hvis du utelukkende har „Bestätigungs-GETs“ i UI-et og brukeren uansett klikker igjen, eller hvis du opererer i et internt, svært stabilt miljø uten kvoter og feil er umiddelbart synlige. Selv da er riktige timeouts og logging nesten alltid fornuftig.

Pragmatisk sjekkliste for produktiv Delphi-REST klientdrift

  • Timeouts: konfigurerbart per endepunkt, realistisk satt, totalt budsjett definert.
  • Retry-Policy: avhengig av HTTP-metode og idempotens, ikke generell.
  • 429-håndtering: evaluer Retry-After, backoff med jitter, hold øye med parallellitet.
  • Avbrytelsesvei: backoff-venting må kunne avbrytes (stopp av tjeneste, brukeravbrytelse).
  • Logging: Correlation-ID, forsøk, forsinkelse, varighet, status/headers – uten secrets.
  • Valgfritt: klientside Rate-Limiter for batch-/paralleldrift.

Konklusjon: Robusthet er en oppførsel, ikke en catch-all-exception-blokk

Med RESTClient i Delphi får du fungerende REST-kall raskt på plass. Produksjonsrobust blir det først når du bevisst definerer timeouts, sikrer gjenforsøk faglig (idempotens!), og respekterer 429 rate-limits med backoff og jitter. Koden for dette er ikke komplisert, men den må være sentralisert, konfigurerbar og godt observerbar. Det er da innsatsen lønner seg: færre „sporadiske“ tickets, bedre diagnose i drift og integrasjoner som ikke mister fotfestet under belastning.

Hvis du vil innføre en slik Retry-/Backoff-Policy for eksisterende Delphi-applikasjoner på en ryddig måte eller dimensjonere den for en ny integrasjon: ta kontakt.

For dette temaet er også Delphi Restclient timeout og retry-strategi Delphi viktige. Artikkelen setter disse aspektene i en forståelig kontekst og viser hva som er viktig i hverdagen.

Diskuter prosjekt eller moderniseringsinitiativ med Net-Base.

Neste trinn

Når et tema blir et reelt prosjekt, bør arkitektur, eksisterende systemer og drift vurderes samlet allerede tidlig i prosessen.

Vi bistår ikke bare med enkeltspørsmål, men også når kodesnutter, legacy-temaer eller portalideer skal utvikles til et robust virksomhetsprosjekt.

  • Eksisterende tilstand, målbildet og tekniske risikoer vurderes samlet.
  • REST, datatilgang, portaler og utrulling blir ikke utsatt som etterfølgende oppgaver.
  • Dere ser tidlig hvilken vei som er økonomisk og driftsmessig levedyktig.

Del innlegg

Del dette innlegget direkte

LinkedIn, X, XING, Facebook, WhatsApp og e-post er umiddelbart tilgjengelige. For Instagram forbereder vi lenke og kort tekst umiddelbart.

E-post

Instagram åpnes i en ny fane. Lenken og kortteksten kopieres først til utklippstavlen.