asyncio.wait_for()
: Оборачивает асинхронную операцию, позволяя установить максимальное время ожидания. Вызывает asyncio.TimeoutError
при превышении времени.try...except
для перехвата исключений, таких как aiohttp.ClientError
(или аналогичные для других библиотек), чтобы обработать сетевые ошибки и ошибки HTTP.tenacity
) для обработки временных сбоев. Важно учитывать идемпотентность операций.aiohttp
).asyncio.wait_for
):
async def fetch_data(url):
try:
async with asyncio.timeout(5): # Таймаут 5 секунд
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
except asyncio.TimeoutError:
print(f"Таймаут при запросе к {url}")
return None
except aiohttp.ClientError as e:
print(f"Ошибка при запросе к {url}: {e}")
return None
Обработка таймаутов и сбоев при взаимодействии с внешними сервисами в асинхронном приложении – критически важная задача для обеспечения надежности и отказоустойчивости.
Вот несколько стратегий и техник, которые можно использовать:
aiohttp
, httpx
). Задавайте таймауты на подключение (connection timeout), на чтение данных (read timeout) и общий таймаут запроса. Это предотвращает "зависание" приложения в ожидании ответа от недоступного сервиса. Пример (aiohttp
):
import aiohttp
import asyncio
async def fetch_data(url):
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10, connect=5, read=5)) as session:
try:
async with session.get(url) as response:
return await response.text()
except asyncio.TimeoutError:
print(f"Timeout error for {url}")
return None
except aiohttp.ClientError as e:
print(f"Client error for {url}: {e}")
return None
async def main():
data = await fetch_data("https://example.com")
if data:
print(data)
if __name__ == "__main__":
asyncio.run(main())
try...except
для перехвата исключений, связанных с сетевыми ошибками (aiohttp.ClientError
, socket.gaierror
, asyncio.TimeoutError
и т.д.).tenacity
).tenacity
):
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
import aiohttp
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10), retry=retry_if_exception_type(aiohttp.ClientError))
async def fetch_data_with_retry(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
return await response.text()
async def main():
try:
data = await fetch_data_with_retry("https://example.com")
print(data)
except aiohttp.ClientError as e:
print(f"Failed to fetch data after multiple retries: {e}")
if __name__ == "__main__":
asyncio.run(main())
async with
для гарантированного освобождения ресурсов (например, закрытия соединений) даже в случае исключений.asyncio.wait_for
. Это предотвращает "зависание" отдельных корутин и блокировку event loop. Пример:
import asyncio
async def my_task():
await asyncio.sleep(5) # Simulate a long-running task
return "Task completed"
async def main():
try:
result = await asyncio.wait_for(my_task(), timeout=2)
print(result)
except asyncio.TimeoutError:
print("Task timed out!")
if __name__ == "__main__":
asyncio.run(main())
Выбор конкретных стратегий зависит от требований к надежности, производительности и сложности вашего приложения. Важно тщательно продумать обработку ошибок и таймаутов, чтобы обеспечить стабильную работу приложения даже при сбоях внешних сервисов.