Комментарий пользователя
Здравствуйте! Делаю запросы к внешним API через requests. Иногда процесс зависает на одном запросе и воркеры перестают обслуживать клиентов. Подскажите, что я упускаю и как это исправить?
Ответ специалиста
Добрый день, Максим! Это классическая ситуация — обычно виноваты два простых момента: нет таймаутов на запросах и нет адекватной стратегии повторов при временных ошибках.
По умолчанию requests.get() может ждать ответ бесконечно, и один «залипший» вызов способен заглушить поток или воркер. Что можно сделать: использовать Session (чтобы рециклировать соединения), настроить Retry с backoff и всегда передавать timeout в виде (connect, read).
Вот шаблон, который можно доработать и вставить в проект:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def make_session(retries=3, backoff=0.5, pool_maxsize=10):
s = requests.Session()
retry = Retry(
total=retries,
backoff_factor=backoff,
status_forcelist=(429, 500, 502, 503, 504),
allowed_methods=frozenset(["HEAD","GET","OPTIONS","POST","PUT","DELETE"]),
respect_retry_after_header=True
)
adapter = HTTPAdapter(max_retries=retry, pool_maxsize=pool_maxsize)
s.mount("https://", adapter)
s.mount("http://", adapter)
return s
А в месте вызова всегда указывайте таймаут и ловите исключения, чтобы процесс не висел:
sess = make_session()
try:
r = sess.get("https://api.example.com/data", timeout=(3.0, 10.0))
r.raise_for_status()
payload = r.json()
except requests.exceptions.Timeout:
print("request timed out")
except requests.exceptions.HTTPError as e:
print("http error", e)
except requests.exceptions.RequestException as e:
print("network error", e)
Есть еще практические моменты, которые часто помогают
- Не включайте ретраи для небезопасных операций без идемпотентности (некоторые POST могут повторяться).
- Логируйте метрики по таймаутам и retry, чтобы быстро увидеть проблемные внешние сервисы.
- Ограничьте параллельность вызовов к одному внешнему API (семафор или очередь), чтобы не создавать thundering herd.
На уровне процесса не полагайтесь только на код — задайте worker timeout в Gunicorn/uWSGI, чтобы один долгий запрос не съедал все воркеры. Для асинхронного стека те же принципы: httpx/aiohttp, таймауты, семафоры и retry-обертки.
Мы продолжим публиковать актуальные инструкции по работе с инфраструктурой. Следите за обновлениями Академии Selectel, чтобы быть в курсе лучших практик.