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
Links
- Real implementation: code_source_simule/pipeline.py
- Quota configuration:
config.ini(QUOTA_NORMAL, QUOTA_ECO, QUOTA_PROTECTION thresholds) - Quota state:
logs/marketstack_quota_usage.json - Decision log: ../01_architecture/key-decisions.md — "Implement Four-Mode Quota Policy"
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.