asyncio.gather з return_exceptions=True додає винятки завдань до свого списку результатів. Тому очікування пакета без винятку не означає, що кожен запит через проксі завершився успішно.

Тримайте пункт призначення й обраний проксі поруч із надісланими awaitable-об'єктами, а потім перевіряйте кожен результат:

outcomes = await asyncio.gather(*jobs, return_exceptions=True)

for (url, proxy), outcome in zip(routes, outcomes):
    if isinstance(outcome, BaseException):
        record_failure(url, proxy, outcome)
    else:
        record_success(url, proxy, outcome)

jobs містить корутини запитів застосунку; routes містить відповідні їм пари (url, proxy) у тому самому порядку. Функції запису — це власна обробка результатів застосунку. gather зберігає порядок входу, навіть коли порядок завершення інший.

Повернений CancelledError дочірнього завдання класифікуйте як скасування, а не звинувачуйте його проксі. Скасування зовнішнього gather усе ще поширюється на незавершених дочірніх завдань; return_exceptions не перетворює це скасування на звичайний успіх.

Обробка HTTP-статусу також належить до операції запиту. aiohttp за замовчуванням не породжує виняток для кожної помилки HTTP, тому повертайте статус або застосовуйте raise_for_status згідно з політикою завдання.

Щойно результати стають видимими, застосунок може відрізняти збої з'єднання від відповідей пункту призначення й вирішувати, яка робота заслуговує ще однієї спроби.

Схожі статті