Net-Base Revista

08.08.2026

RESTClient en Delphi: robust davant de timeouts, reintents i límits de taxa 429 amb backoff

Si les crides a REST a Delphi es pengen esporàdicament, activen timeouts o retornen amb el codi 429 per limitació de taxa, no n'hi ha prou amb 'enviar-ho una altra vegada'. Aquest article pràctic mostra com, amb RESTClient, aplicar timeouts controlats, reintents segurs, backoff amb jitter i un registre clar i estructurat.

08.08.2026

Del tema de la revista a la pràctica del projecte

Pàgines de serveis i tècniques pertinents per a l'article

Una crida REST és en teoria senzilla: petició fora, resposta dins, llest. En la pràctica, però, les integracions productives rarament fallen per una «URL errònia», sinó per casos marginals en l’operació: timeouts esporàdics, problemes temporals de DNS o TLS, sistemes downstream sobrecarregats, o 429 (Too Many Requests) perquè un API-Gateway drosseja. Precisament aquí es separa un prototip de demo d’una integració operable a llarg termini.

Aquest article mostra com tu, amb el RESTClient en Delphi, estableixes camins de comunicació robustos: definicions de timeout clares, reintents dirigits només on són segurs des del punt de vista funcional i tècnic, i un comportament de backoff que respecti els límits de taxa en lloc d’empitjorar-los. L’enfoc no és el «codi maco», sinó el comportament sota càrrega, la capacitat de depuració, una classificació neta d’errors i la qüestió de quan realment val la pena l’esforç addicional.

Per què els Timeouts, Retries i 429 en entorns reals apareixen junts

En xarxes d’empresa, les crides REST rarament van «directament a Internet». Són típiques les cadenes de proxy, la terminació TLS, API-Gateways, WAFs (Web Application Firewall) i diversos salts interns. Cada element pot tenir els seus propis timeouts i límits. Un timeout al costat del client pot significar:

  • El servidor no ha respost (sobrecàrrega, deadlock, sistema downstream bloquejat).
  • La resposta ha arribat, però massa tard (camí de xarxa deficient, pèrdua de paquets, congestió).
  • T’has bloquejat tu mateix: timeouts massa curts o un UI-/main-thread que bloqueja.

Al mateix temps, els reintents «naïfs» sovint provoquen més problemes: si un servidor ja està al límit, els reintents augmenten la càrrega i converteixen un petit coll d’ampolla en una incidència. Amb un 429 això es fa encara més evident: un límit de taxa és una indicació explícita d’enviar-ne menys o de tornar més tard. Un client sense backoff es comporta com un generador de DoS, però de manera involuntària.

La robustesa no s’aconsegueix per «reintentar a tot arreu», sinó mitjançant un model de decisió coherent: quins errors són transitoris (temporals), quins són permanents, quines peticions són reintentables (idempotents), i com controles els temps d’espera perquè el teu sistema es mantingui estable.

Configurar timeouts amb cura: què significa exactament «Timeout» en el RESTClient en Delphi?

Un obstacle habitual: «timeout» no és sempre el mateix. Segons l’stack hi ha fases diferents. Encara que els components Delphi-REST encapsulin moltes parts, hauries de tenir el model al cap:

  • Connect-Timeout: temps fins que s’estableix la connexió TCP (incloent DNS/TLS segons la implementació).
  • Read/Response-Timeout: temps fins que arriben els bytes del servidor o fins que la resposta està completa.
  • Gesamt-Timeout: límit superior per a tota la crida inclosos els reintents.

En la pràctica, un timeout massa curt és almenys tan perillós com un massa llarg: generes errors artificials que després es reintenten i així creen càrrega. A l’inrevés, un timeout massa llarg bloqueja worker-threads, slots de cua o la capacitat de resposta de la UI. Per a operació i administració és important que els timeouts siguin configurables (p. ex., per endpoint) i que s’enregistrin en el log.

Recomanació pràctica: dues capes en lloc d’un sol valor

Per a les crides REST en software empresarial s’han demostrat útils dues capes:

  • Call-Timeout (per petició): límit superior realista que s’ajusti al cas d’ús.
  • Job-Timeout (a nivell superior): si tens un processament per lots o un job de sincronització, limita la durada total i finalitza-ho de manera neta.

Així evites que una única resposta d’API esperi indefinidament i, alhora, que un job nocturn s’executi «fins a migdia» a causa de molts reintents.

Decidir sobre reintents: no tècnic, sinó funcional

Si un reintent està permès no és una qüestió purament tècnica. El terme clau és idempotència: una petició és idempotent si executar-la diverses vegades produeix el mateix efecte que fer-la una sola vegada. Exemples típics: GET és idempotent, PUT sovint també (si estableixes l’objecte destí completament), DELETE habitualment també. POST sovint no és idempotent (p. ex. «crear una nova ordre»).

Per què és crucial? Un timeout pot significar que el servidor sí que va processar la petició, però la resposta no va arribar al client. Si després tornes a enviar un POST a cegues, generaràs duplicats. Això és en producció un cas clàssic de «error fantasma»: a l’aplicació apareix «Timeout», però al backend hi ha registres duplicats.

La base segura: reintents només per a operacions clarament reintentables

Una regla robusta que ha demostrat la seva validesa en integracions:

  • GET: reintentable en cas d’errors transitoris.
  • PUT/DELETE: reintentable si la teva API ho defineix clarament des del punt de vista funcional (per ex. l’ID del recurs és estable) i el servidor implementa idempotència correctament.
  • POST: només reintentable si disposes d’una estratègia Idempotency-Key (ID de petició únic a nivell funcional que evita duplicats al costat del servidor) o si el POST és semànticament idempotent (rar, però possible).

Si no controles l’API, aquí és on, com a responsable tècnic, has de prendre una decisió: o acceptes «no reintentar POST» (i implementes millors missatges d’error/mecanismes de resincronització), o negocies amb el proveïdor de l’API una estratègia Idempotency-Key o un model que permeti la desduplicació.

429 Too Many Requests: respectar els límits de taxa en lloc de «reintentar a cegues»

Grafik eines API-Gateways mit gedrosselten Requests und Backoff-Abständen
Amb 429 ajuda un backoff controlat: menys reintents simultanis, recuperació més estable.

HTTP 429 no és un «missatge d’error molest», sinó un mecanisme de control. En entorns empresarials el 429 sovint prové de:

  • API-Gateway amb límits Token-Bucket/Leaky-Bucket (Rate Limiting).
  • Cloud-APIs amb límits per tenant per minut/hora.
  • Serveis interns que es protegeixen contra pics de càrrega.

Per al client això significa: reintents sí, però controlats. Són importants dues coses:

  • Analitzar l’encapçalament Retry-After, si existeix (segons o data HTTP).
  • Fer servir Backoff quan no arriba un Retry-After o quan a més aplicis jitter.

La trampa més habitual: tractar el 429 com un 500 («error de servidor, reintentar immediatament»). Això només reforça la limitació. Millor: 429 és un senyal per esperar activament i, si cal, reduir la paral·lelitat.

Backoff amb jitter: per què sense aleatorietat tot col·lapsa de manera sincronitzada

Backoff exponencial vol dir que incrementes el temps d’espera després de cada intent fallit (p. ex. 200 ms, 400 ms, 800 ms …). jitter és una component aleatòria que evita que molts clients tornin a trucar simultàniament. Sense jitter sovint passa a la pràctica això: s’activa un límit, 50 clients reben 429, tots esperen exactament 1 segon i tornen a enviar alhora. Resultat: de nou 429, i tens un problema de „Thundering Herd“.

Un enfoc pràctic és «Full Jitter» o «Equal Jitter»: calcules una finestra de backoff i després tries un temps d’espera aleatori dins d’aquesta finestra. Sembla un detall, però en operació fa la diferència entre una recuperació estable i un brunzit constant.

Un patró net: encapsular les crides a REST, en lloc d’estendre bucles de reintents per tot arreu

Si implementes reintents/backoff „ad hoc“ a cada punt de crida, ràpidament apareix un comportament inconsistent: un endpoint reintenta agressivament, un altre gens, el registre és incomplet i els administradors només veuen „errors esporàdics“. Esdevé robust quan defineixes una via de crida centralitzada:

  • Un wrapper al voltant de RESTClient/RESTRequest que apliqui la política (timeout, reintents, backoff).
  • Un objecte de resultat unificat: codi d’estat, durada, comptador d’intents, si s’escau última excepció.
  • Registre estandarditzat (Request-ID/Correlation-ID, endpoint, mètode HTTP, capçaleres rellevants).

Aquest és el punt en què realment compensa afegir codi addicional: obteniu un comportament reproduïble, millors logs i podeu configurar polítiques per sistema de destinació sense reorganitzar l’aplicació.

Matriu de decisions per polítiques (breu i pràctica)

Per a la majoria d’integracions n’hi ha prou amb una matriu senzilla que implementis al wrapper:

  • Reintent en: errors de xarxa/caigudes de connexió, 408, 429, 502, 503, 504 (segons el contracte de l’API).
  • No reintentar en: 400/401/403/404 (habitualment errors de configuració/autenticació/petició), 409/422 (conflictes lògics/validació), així com en POST sense clau d’idempotència.
  • Màx. intents: mantenir-lo petit (sovint 2–4 intents són suficients), i compensar amb millor monitorització.
  • Màx. backoff: limitar-lo (p. ex. pocs segons fins a un minut), altrament bloquejaràs massa workers.

Important: aquestes regles no són universals. Un 404 pot ser transitori en cas d'“eventual consistency“, un 409 pot ser transitori amb estratègies de locking. La diferència és que aleshores serà una desviació conscient, no un comportament aleatori.

Cas límit concret: timeout després d’un POST — s’ha desat ara o no?

Diagrames en paper i apunts que visualitzen un estat de POST incert després d'un timeout
El timeout després d’un POST és perillós: sense idempotència l’estat queda tècnicament incert.

Aquest és el clàssic que es reprodueix rarament de forma neta en el depurador: tu envies un POST (p. ex. „Ticket anlegen“), el teu client obté un Read-Timeout, i l’usuari fa clic „de nou“. Al backend, però, el ticket ja existeix. Sense mesures de mitigació es generen duplicats o inconsistències.

Només és robust amb una de les tres estratègies següents:

  • Idempotency-Key: generes per cada operació funcional una identificació única de petició (p. ex. GUID), l’envies com a header i el servidor garanteix un processament deduplicat.
  • Client-seitige Deduplizierung: emmagatzemes localment peticions pendents amb una ID pròpia i, després del timeout, fas una comprovació d’estat (p. ex. un GET per la clau funcional). Això és més costós i no sempre possible.
  • Kein Retry: notifiques clarament que l’estat és desconegut i implementes un procés de resincro manual/automàtic (p. ex. una reconciliació posterior).

Si construeixes integracions per a operacions, «estat desconegut» és una categoria vàlida. No intentis codificar fora la incertesa. Registra-la als logs, fes-la visible i proporciona un camí de reconciliació.

Backoff-Design in der Praxis: Grenzwerte, Parallelität und Cancel

Un backoff no és només „Sleep“. L’has de situar en el context de la teva aplicació:

  • Parallelität: si tens 20 threads i tots esperen, 20 threads queden bloquejats. Per a serveis això sovint és acceptable; per a aplicacions d’escriptori, no tant.
  • Cancel: un usuari cancel·la, el servei s’atura, un job finalitza. L’espera del backoff ha de ser cancel·lable; si no, els processos d’aturada o shutdown es poden quedar penjant.
  • Fairness: diversos endpoints no s’han d’empassar els recursos entre ells. Els rate-limits sovint són per token o per endpoint; el teu wrapper hauria de poder controlar-ho per sistema de destinació.

Una aproximació neta és: implementar el backoff dins d’una funció que esperi a petits intervals i comprovi un flag de cancel·lació (p. ex. Event/Token). Això no és un luxe: just aquest punt decideix si els Windows- und Linux-Services s’aturen correctament o es „penjen“ a la consola del Service Control Manager.

Maximaldauer und „Budget“ pro Call

Una implementació robusta de reintents no funciona només amb „max tries“, sinó també amb un pressupost de temps. Exemple: permets com a màxim 10 segons de temps total per la crida incloent reintents. Així, un intent individual no pot bloquejar 30 segons de sobte només perquè un timeout està mal configurat. Per a administradors i operacions això és or, perquè limita pics de latència i estabilitza cues.

Debugging und Betriebsdiagnose: Ohne gute Logs sind Retries unsichtbare Fehlerverstärker

Escena d'estació de treball amb logs desenfocats i context esbossat per a Request-IDs i reintents
Amb Correlation-ID, comptador d’intents i durada, els reintents es tornen rastrejables en producció.

Els reintents sense registre són perillosos, perquè al final només sentiràs «a vegades tarda». Si vols ser robust, necessites logs que no només mostrin excepcions, sinó que proporcionin context:

  • Correlation-ID: una Request-ID que generes per cada crida i conserves en tots els reintents.
  • Número d’intent i Delay (Backoff).
  • HTTP-Status i headers seleccionats (en particular Retry-After, RateLimit-Header si existeixen).
  • Durada per intent i temps total.
  • Endpoint (Host + Pfad), però sense dades sensibles als logs (Tokens, dades personals).

Per als responsables tècnics, això també és la palanca per ajustar els llindars: veuràs si els Timeouts «sempre als 3 segons» passen (probablement massa curts) o si els 429 arriben en onades (paral·lelisme massa alt, Backoff massa feble o manca de Rate-Limits al costat del client).

Falles típiques en els logs

  • Masses de payload: registrar completament els cossos JSON sembla útil, però explota amb fitxers/adjunts i genera problemes de privacitat. Millor: hash/mida, Content-Type, i si cal logging de depuració dirigit mitjançant feature-flag.
  • Cap diferenciació Timeout vs. Cancel: una crida interrompuda no és un error en el mateix sentit que un Timeout. Separa-ho, sinó els administradors perseguiran errors fantasma.
  • El reintent amaga la causa inicial: si l’intent 1 té un error TLS i l’intent 2 té èxit, encara vols saber que hi va haver una intermitència TLS. Això és un senyal d’alerta primerenca.

Rate-Limiting al costat del client: quan has de controlar la càrrega tu mateix

429 és la resposta del servidor. En molts escenaris, però, té sentit frenar ja al costat del client abans de generar cap 429. Això és especialment rellevant si tu:

  • tens treballs en lots (p. ex. reconciliació de dades a la nit) i l’API només permet X peticions per minut.
  • utilitzes diversos Worker/Threads i envies les peticions en paral·lel.
  • tens diverses instàncies de procés en execució (p. ex. Terminalserver o diversos serveis).

Pràcticament això vol dir: implementes un petit rate-limiter (p. ex. Token-Bucket) per sistema de destinació o per API-Key. Això redueix els 429, estabilitza el rendiment i fa que els temps d’execució siguin més previsibles. Per a l’operació i la planificació de capacitat sovint és més valuós que «un altre reintent».

Important: Rate-Limiter i Backoff es complementen

El Rate-Limiter et manté per sota del límit en funcionament normal. El Backoff és la reacció quan tot i així reps 429 o una sobrecàrrega temporal. Qui només té Backoff acaba anant «contra la paret» i frenant-se. Qui només té Rate-Limiter reacciona malament davant límits imprevistos o quotes compartides (p. ex. si diversos sistemes utilitzen el mateix API-Key).

Seguretat i Compliance: els reintents no han d’amagar problemes d’autenticació

A les empreses, l’autenticació i l’autorització són sovint l’«error» més habitual després del desplegament: Tokens caducats, credencials de client mal configurades, excepcions de proxy inexistents. Aquí els reintents no serveixen i poden fins i tot ser perjudicials, perquè omplen els logs i activen mecanismes de bloqueig (p. ex. bloqueig de comptes, límits de velocitat als punts finals d’autenticació).

Regla pràctica: 401/403 mai no reintentar (excepte si tens un maneig conscient de Token-Refresh). Si implementes Token-Refresh, separa-ho clarament del mecanisme de reintents: primer renova el token, després envia la petició una vegada de nou. I registra explícitament que s’ha fet un refresh.

Quan val la pena l’esforç — i quan no

Els reintents i el backoff robustos no són un fi en si mateixos. Convé especialment quan s’aplica almenys un dels punts següents:

  • La integració és crítica per al negoci (p. ex., captura de comandes, enviament, facturació).
  • L’API és externa o està operada intern en règim de «best effort» i no en tens el control complet.
  • Tens pics de càrrega (p. ex., finestres de processament per lots, tancament de mes) i vols passar-los de manera estable.
  • L’executes com a servei/daemon i ha de ser aturable de manera planificable i neta.

És menys necessari si només tens «Bestätigungs-GETs» a la UI i l’usuari de totes maneres fa clic de nou, o si treballes dins d’un entorn intern molt estable sense quotes i els errors són visibles immediatament. Tot i així, en aquests casos els timeouts ben definits i el logging gairebé sempre són útils.

Llista de comprovació pragmàtica per a l’explotació productiva del client Delphi-REST

  • Timeouts: configurables per endpoint, escollits de manera realista, pressupost total definit.
  • Retry-Policy: depenent del mètode HTTP i de la idempotència, no de manera generalitzada.
  • 429-Handling: valorar Retry-After, backoff amb jitter, vigilar la paral·lelitat.
  • Camí d’aturada: l’espera de backoff ha de poder interrompre’s (Service-Stop, User-Cancel).
  • Logging: Correlation-ID, Attempt, Delay, durada, Status/Headers – sense Secrets.
  • Opcional: rate-limiter del costat client per a operacions per lots/paral·leles.

Conclusió: la robustesa és un comportament, no un bloc catch-all d’excepcions

Amb el RESTClient en Delphi obtindràs crides REST operatives ràpidament. Però només serà robust en producció quan defineixis conscienciosament els timeouts, asseguris els reintents des d’un punt de vista tècnic (idempotència!), i respectis els límits 429 amb backoff i jitter. El codi no és complicat, però ha d’estar centralitzat, configurable i fàcilment observable. És precisament llavors quan compensa l’esforç: menys incidències «esporàdiques», diagnosi operativa millorada i integracions que no fallen sota càrrega.

Si vols implantar correctament una política de reintents/backoff en aplicacions Delphi existents o dimensionar-la adequadament per a una nova integració: Contacta’ns.

Per a aquest tema són també importants Delphi Restclient Timeout i Retry-Strategie Delphi. L’article situa aquests aspectes de manera comprensible i mostra en què cal centrar-se en el dia a dia.

Parlar d’un projecte o d’una iniciativa de modernització amb Net-Base.

Pas següent

Quan d'un tema se'ndevé un projecte real, s'han de considerar aviat i de manera conjunta l'arquitectura, els actius existents i l'operació.

No només donem suport en qüestions puntuals, sinó també quan, a partir de fragments de codi font, temes de sistemes heredats o idees de portal, ha de sorgir un projecte empresarial sòlid.

  • L'estat actual, la visió objectiu i els riscos tècnics s'avaluen conjuntament.
  • REST, accés a dades, portals i desplegament no es posposaran com a efectes retardats.
  • Veu aviat quin camí és viable des del punt de vista econòmic i operatiu.

Comparteix la publicació

Comparteix aquesta publicació directament

LinkedIn, X, XING, Facebook, WhatsApp i correu electrònic estan disponibles immediatament. Per Instagram preparem l'enllaç i un text curt immediatament.

Correu electrònic

Instagram s'obre en una pestanya nova. L'enllaç i el text curt es copien prèviament al porta-retalls.