Повторы запросов и HTTP-кеш
Повторы запросов
import os
from duckonet import HttpClient, RetryPolicy
with HttpClient(
api_key=os.environ['DUCKONET_API_KEY'],
retry_policy=RetryPolicy(max_retries=2),
) as client:
response = client.get('https://example.com/status')
print(response.attempt_count)
RetryPolicy | По умолчанию | Ограничение / смысл |
|---|---|---|
max_retries | 0 | Дополнительные попытки, 0–10; всего не более 1 + max_retries. |
methods | ('GET', 'HEAD', 'OPTIONS') | Явный кортеж HTTP-методов; CONNECT запрещён. Остальные методы добавляются только при осознанном разрешении повторной операции. |
statuses | (408, 425, 429, 500, 502, 503, 504) | Кортеж кодов 400–599; 401, 403 и 407 не допускаются. |
errors | ('dns', 'connect', 'timeout', 'receive', 'http2', 'http3') | Разрешённые группы сетевых ошибок. |
backoff_factor | 0.25 | Начальная задержка в секундах, удваивается при последующих повторах; диапазон 0–300. |
max_delay | 30 | Верхний предел одной задержки в секундах, 0–300. |
jitter | 0.1 | Относительный разброс задержки, 0–1. |
respect_retry_after | True | Учитывать единственный корректный Retry-After: секунды либо HTTP-дата, в пределах общего бюджета и max_delay. |
Все числовые задержки должны быть конечными. Ошибки аргументов, лицензии, проверки TLS-сервера и отмена не превращаются в автоматический повтор. После передачи пользователю части потокового ответа повтор не начинается. Для отправляемого тела нужен повторяемый источник: байты, поддержанный seekable-источник или фабрика из существующего upload API.
Повтор POST может повторить действие на сервере даже при потере ответа. Библиотека не может гарантировать его безопасность по одному Idempotency-Key; разрешайте такие методы только с учётом контракта вашего сервера. Cookies обрабатываются из реально полученных ответов; повторы не перезапускают полный внешний прогон и не выбирают другой профиль.
RetryAttempt(attempt, reason, status_code, delay_seconds) описывает принятое решение о повторе. Причины и группы ошибок конечны; объект не содержит текст тела, заголовки или ключи. retry_history не включает отдельно каждый redirect.
Для собственной обвязки policy.permits(method, retries) проверяет метод и число уже назначенных повторов; policy.error_group(error) возвращает разрешённую группу для известной нативной ошибки либо None; policy.delay(retries, response=None) вычисляет задержку в секундах. Аргумент retries у delay — целый индекс 0–10. Эти методы сами не отправляют запрос и не ожидают задержку; обычному приложению достаточно передать политику клиенту.
Кеш HTTP-ответов
import os
from duckonet import HttpClient, MemoryResponseCache
cache = MemoryResponseCache(max_entries=128)
try:
with HttpClient(api_key=os.environ['DUCKONET_API_KEY'], response_cache=cache) as client:
response = client.get('https://example.com/public-data')
print(response.from_cache)
finally:
cache.close()
| Конструктор | Параметры по умолчанию |
|---|---|
MemoryResponseCache | max_entries=256, max_bytes=16777216, max_entry_bytes=1048576, default_ttl=0, max_ttl=3600 |
FileResponseCache(directory, ...) | max_entries=256, max_bytes=16777216, max_entry_bytes=524288, default_ttl=0, max_ttl=3600 |
Общие пределы: max_entries от 1 до 10000; max_bytes от 1 до 1073741824. max_entry_bytes от 1 до 67108864 для памяти и до 524288 для файлового backend. TTL задаются в секундах от 0 до 2592000. default_ttl=0 не кеширует ответ без подходящего срока свежести. max_ttl ограничивает срок, вычисленный из серверных Cache-Control/Expires с учётом Date и Age.
Файловый backend получает отдельный закрытый каталог и сохраняет ограниченные JSON-записи с атомарной заменой. Повреждённая или просроченная запись считается промахом; исполняемый формат и pickle не используются. Объект кеша остаётся во владении приложения. close() памяти очищает её; close() файлового кеша закрывает объект, сохраняя записи на диске. Для удаления принадлежащих ему записей вызовите clear() до close().
Кеш применяется только к полным буферизованным ответам GET/HEAD со статусами 200, 203, 204, 404, 410. Ответы после redirect, запросы с телом, streaming и WebSocket его не используют. no-cache, no-store, private, Vary: *, Range/206, авторизация, cookies и Set-Cookie исключают использование. Изменения сетевых/TLS-настроек также консервативно обходят кеш. Условной валидации ETag/304 и выдачи просроченных ответов нет.
Ключ учитывает адрес, метод, эффективные заголовки, аккаунт, профиль, маршрут и namespace. Права проверяются и при чтении из кеша. Наличие сохранённого тела не даёт права обойти лицензию. Не используйте общий backend для намеренного хранения секретных данных приложения; незнакомый библиотеке пользовательский заголовок не обязательно распознаётся как секрет.
Для собственного backend наследуйте ResponseCache(default_ttl=0, max_ttl=3600) и реализуйте get(key), put(key, entry), clear(), close(). get возвращает CacheEntry либо None; put — удалось ли сохранить запись. Ключ — 64 строчных hex-символа. CacheEntry(status_code, protocol, headers, body, created_at, expires_at, initial_age=0) содержит bytes-тело, пары заголовков и Unix-время; size учитывает тело и заголовки. Ваш backend обязан обеспечить ограничения, изоляцию и безопасность своей реализации. CacheError сообщает об ошибке состояния кеша.