How to Implement Retry with Exponential Backoff for Cloud API 429 Errors in Python

Implement a retry-with-backoff loop in Python to handle 429 throttling errors from cloud APIs, using exponential delay between attempts.

Easy Python 3.9+ Aug 9, 2026 Cloud + Python 13 views 0 copies

Requires third-party packages — install first
pip install requests

Python code

30 lines
Python 3.9+
import time
import random
import requests


def api_call(attempt):
    """Mock cloud API that returns 429 for the first two attempts."""
    if attempt < 2:
        return 429, "Too Many Requests"
    return 200, {"data": "success"}


def retry_with_backoff(api_func, max_retries=3, base_delay=0.1):
    for attempt in range(max_retries):
        status, body = api_func(attempt)
        if status == 429:
            delay = base_delay * (2 ** attempt)
            print(f"Attempt {attempt + 1}: 429, retrying in {delay:.2f}s")
            time.sleep(delay)
        else:
            print(f"Attempt {attempt + 1}: {status} - {body}")
            return status, body
    print("Max retries exceeded")
    return None


if __name__ == "__main__":
    random.seed(42)
    result = retry_with_backoff(lambda attempt: api_call(attempt))
    print("Final result:", result)

Output

stdout
Attempt 1: 429, retrying in 0.10s
Attempt 2: 429, retrying in 0.20s
Attempt 3: 200 - {'data': 'success'}
Final result: (200, {'data': 'success'})

How it works

The retry_with_backoff function loops through a maximum number of attempts, calling the API function each time. When the status code is 429, it calculates a delay using exponential backoff (base_delay * (2 ** attempt)) and sleeps to respect the throttle. If the call succeeds (status != 429), it returns the result immediately, avoiding unnecessary waits. The loop tracks the attempt index so the delay grows with each retry, a standard pattern in cloud SDKs. Using random.seed(42) here is optional—it just makes the example reproducible, but the actual retry logic does not rely on randomness.

Common mistakes

  • Not sleeping between retries, causing immediate hammering of the API
  • Using a fixed delay instead of exponential backoff, which increases load on already-throttled services
  • Forgetting to handle other error status codes (e.g., 5xx) that should also be retried
  • Exceeding resource limits by retrying indefinitely without a max attempts cap

Variations

  1. Use `tenacity` library with `@retry(wait=wait_exponential())` to simplify retry logic
  2. Parse the `Retry-After` header from the 429 response to set a custom delay

Real-world use cases

  • Making authenticated calls to AWS, GCP, or Azure APIs that rate-limit requests per second
  • Fetching data from REST endpoints like GitHub or Stripe that return 429 when quotas are exceeded
  • Processing large batches of API requests in a data pipeline where throttling is common

Sponsored

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from Cloud + Python

Related tutorials and quizzes for this topic.