Yeda AI Tips · #158

Español

Never Hand-Roll Retry Logic

Your retry loop is retrying errors that can never succeed. A 500 will probably clear on the next attempt; a 400, 401, or 422 will fail identically every single time — so a naive for attempt in range(5) loop just multiplies the same doomed request by five, hammers a struggling service, and burns your latency budget for nothing.

Why hand-rolled retries go wrong

The three-line retry loop everyone writes gets the easy part right and the hard parts wrong:

Backoff math, jitter, and circuit-breaker state are subtle enough that a battle-tested library will do it better than the code you write under deadline.

The rule: retry transient, skip client errors

StatusMeaningRetry?
408, 429, 500, 502, 503, 504Timeout, rate-limit, server errorYes — transient
Connection reset / DNS / socket timeoutNetwork blipYes — transient
400, 401, 403, 404, 422Bad request, auth, not-found, validationNo — permanent

The one exception worth knowing: 429 Too Many Requests is a 4xx but it is retryable — honor its Retry-After header instead of retrying blindly.

Reach for a library

Python — tenacity:

from tenacity import (retry, stop_after_attempt,
                      wait_random_exponential, retry_if_exception_type)

@retry(
    retry=retry_if_exception_type(TransientError),  # skip 4xx
    wait=wait_random_exponential(multiplier=1, max=60),  # backoff + jitter
    stop=stop_after_attempt(5),
)
def call_api():
    ...

wait_random_exponential gives you exponential backoff and jitter in one strategy; retry_if_exception_type is where you gate on transient-only errors.

JavaScript — p-retry: throw AbortError to stop immediately on a client error, without consuming the remaining attempts.

import pRetry, {AbortError} from 'p-retry';

await pRetry(async () => {
  const res = await fetch(url);
  if (res.status >= 400 && res.status < 500 && res.status !== 429) {
    throw new AbortError(res.statusText); // permanent — stop now
  }
  if (!res.ok) throw new Error(res.statusText); // transient — retry
  return res.json();
}, {retries: 5, factor: 2});

Power section: make retries actually safe

A retry re-sends a request the server may have already processed. That is only safe if the operation is idempotent — running it twice has the same effect as running it once.

Retry the transient, skip the 4xx, key your writes, and bound the loop — then let a library carry the math.

Resources

<div class="cta">

Building an AI feature? Yeda AI designs, audits, and ships production LLM systems.

Talk to us · Read the blog

</div>