Handling Failed Requests

Managing failed requests using a retry mechanism with exponential backoff, jitter, and a maximum cap.

Overview

When your application communicates with another service (via an API), things won't always go as planned. Sometimes the internet hiccups, or the server you're trying to reach is temporarily overwhelmed. If your app gives up and fails immediately, your users will have a frustrating, buggy experience.

To address this, we recommend using a retry mechanism. However, retrying as fast as possible is dangerous—it can overwhelm the server even more, effectively acting like a self-inflicted cyberattack.

To do this safely and professionally, implement three key concepts: Exponential Backoff, Jitter, and a Max Cap.


Core Concepts

ConceptPurpose
Exponential BackoffEach retry waits progressively longer (1s → 2s → 4s → 8s …), giving the service time to recover.
JitterIntroduces randomness to the wait time, preventing multiple clients from retrying at the same time.
Max CapSets a ceiling on the delay to prevent wait times from becoming unreasonably long.

The Formula

delay = min(base × 2^attempt, max_cap)
actual_wait = random(0, delay)

This pattern is an industry standard used by AWS, Google, Stripe, and virtually every major API provider. Implementing it will make your application more reliable, more respectful of the services you depend on, and a better citizen of the internet.


Suggested Starting Configuration

The table below reflects common patterns recommended across major API provider documentation.


SettingRecommendedWhy
Max retries3–5Enough to ride out brief issues
Base delay1 secondGives the server a moment to breathe
Max cap15–30 secondsBalances patience with user experience
Jitter typeFull (random between 0 and delay)Best spread of retry traffic

These values are a reasonable starting point based on common industry patterns. Adjust them to your use case — a user-facing checkout flow may need shorter wait times and fewer retries than a background data sync.


Putting It All Together

Here's what a complete strategy looks like:

SETTINGS:
- Max retries: 5
- Base delay: 1 second
- Max cap: 30 seconds
- Jitter: random value between 0 and the current delay

FOR each attempt:
    1. Make the API request
    2. If it succeeds → great, you're done!
    3. If it fails:
        a. Calculate delay: min(base × 2^attempt, max_cap)
        b. Add jitter: random(0, delay)
        c. Wait that long
        d. Try again
    4. If all retries are exhausted → give up and report the error

Example

Attempt 1: Request fails
  → Calculated delay: min(1 × 2⁰, 30) = 1 second
  → With jitter: random(0, 1) = 0.6 seconds
  → Wait 0.6 seconds...

Attempt 2: Request fails
  → Calculated delay: min(1 × 2¹, 30) = 2 seconds
  → With jitter: random(0, 2) = 1.3 seconds
  → Wait 1.3 seconds...

Attempt 3: Request fails
  → Calculated delay: min(1 × 2², 30) = 4 seconds
  → With jitter: random(0, 4) = 2.8 seconds
  → Wait 2.8 seconds...

Attempt 4: Request succeeds! (end)

Which Responses to Retry

✅ DO:

  • Only retry on temporary errors. Server busy (503), timeout (408), rate limited (429), and network errors are good candidates.
  • Set a maximum number of retries (3–5 is typical). Don't retry forever.
  • Log every retry to diagnose issues later. Record failed attempts even if a request succeeds on the third try. Tracking these retries helps reveal underlying API health problems.
  • Respect Retry-After headers. Some APIs tell you exactly how long to wait — always honor that.

🚧

Monitor response headers

If a response includes a Retry-After header, always use that value instead of your calculated delay.


❌ DON'T:

  • Don't retry on permanent errors. A "401 Unauthorized" or "404 Not Found" won't fix itself no matter how many times you try (unless it is the result of a race condition that will resolve given more time).
  • Don't retry requests that change data (like payments or order submissions) without being careful — you might accidentally charge someone twice.
  • Don't set your cap too high. If a user is waiting, 30 seconds is usually the practical limit before the experience becomes unacceptable.
  • Don't ignore the underlying problem. If you're retrying constantly, something deeper is wrong.

Some examples:

Safe to RetryDo Not Retry
408 Request Timeout400 Bad Request
429 Too Many Requests401 Unauthorized
500 Internal Server Error403 Forbidden
502 Bad Gateway404 Not Found
503 Service Unavailable422 Validation Error
Network / connection errors

Contacting Support

If, despite your best efforts, you encounter a recurring error that your retry mechanism cannot resolve, feel free to contact Guesty's API Support Team, providing the following:

  1. A summary of the issue, including your expected outcome and the actual outcome
  2. URL to the documentation for the API resource with the issue
  3. Your exact workflow that results in this error, including:
    1. Each request written in cURL
    2. The response codes and messages for each request
    3. The x-request-id from each response header
    4. Timestamps from the events (if possible)