Aller au contenu

Retry Strategies

Context

This project calls the Marketstack API for stock price enrichment. The API has a 10,000 request/month limit. Without controlled retry logic, a single pipeline run can deplete the quota budget, block all enrichment for the rest of the month, or silently re-submit already-enriched tickers.

Two levels of retry are required: 1. Request-level: transient HTTP failures (5xx, network timeout) — retry immediately with exponential backoff 2. Quota-level: monthly limit approaching or exhausted — block pipeline automatically until next month

Details

Request-level retry (exponential backoff)

function fetch_with_retry(url, max_attempts=3):
    wait = 1 second
    for attempt in 1..max_attempts:
        response = http_get(url)
        if response.success:
            return response
        if response.is_rate_limit_error (429):
            log_warning("Rate limit hit, waiting", wait)
            sleep(wait)
            wait = wait * 2   # exponential backoff
        else if response.is_transient_error (5xx, timeout):
            log_warning("Transient error, retrying", attempt)
            sleep(wait)
            wait = wait * 2
        else:
            raise PermanentError(response)   # 4xx errors are not retried
    raise MaxRetriesExceeded

Key rule: Only retry on transient errors (5xx, 429, timeout). Never retry on 4xx errors (client errors are not retried — they indicate a problem with the request itself).

Quota-level blocking (four-mode policy)

function check_quota_before_enrichment(quota_used, quota_limit):
    ratio = quota_used / quota_limit

    if ratio < 0.65:   # Normal mode
        proceed_with_full_enrichment()
    elif ratio < 0.80:  # Eco mode
        proceed_with_reduced_enrichment(skip_already_enriched=True)
    elif ratio < 0.95:  # Protection mode
        enrich_only_missing_prices()
        alert_operator("Quota in protection mode")
    else:               # Blocked mode
        skip_all_enrichment()
        alert_operator("Quota exhausted — enrichment blocked until next month")
        log_quota_event("blocked", quota_used)

Thresholds are operator-configurable in config.ini — no code change required.

Targeted retry (avoid re-enriching)

function get_tickers_needing_enrichment(all_tickers):
    return [t for t in all_tickers if t.price IS NULL or t.price == 0]
    # Never re-submit tickers that already have prices

Examples

Debugging a quota limit error: Check logs/marketstack_quota_usage.json for current quota usage. If quota_used / quota_limit >= 0.95, the pipeline is in blocked mode — no action required until next month. If between 0.80–0.95, check config.ini thresholds and verify the protection mode behavior is as expected.