Рекомендации по откату / дросселированию асинхронных запросов - PullRequest
0 голосов
/ 12 февраля 2020

Сценарий : мне нужно собрать разбитые на страницы данные из API веб-приложения, для которого ограничение вызовов составляет 100 в минуту. Объект API, который мне нужно вернуть, содержит 100 элементов на страницу, всего 105 и растущие страницы (всего ~ 10500 элементов). Синхронный код занимал приблизительно 15 минут для извлечения всех страниц, поэтому тогда не было никакого беспокойства о превышении пределов вызовов. Однако я хотел ускорить извлечение данных, поэтому я реализовал асинхронные вызовы, используя asyncio и aiohttp. Данные теперь загружаются за 15 секунд - хорошо.

Проблема : я сейчас достигаю лимита вызовов, таким образом получая 403 ошибки за последние 5 или около того вызовов.

Предлагаемое решение Я реализовал try/except, найденный в функции get_data(). Я выполняю вызовы, а затем, когда вызов не был успешным из-за 403: Exceeded call limit, я возвращаюсь на back_off секунд и повторяю до retries раз:

async def get_data(session, url):
    retries = 3
    back_off = 60  # seconds to try again
    for _ in range(retries):
        try:
            async with session.get(url, headers=headers) as response:
                if response.status != 200:
                    response.raise_for_status()
                print(retries, response.status, url)
                return await response.json()
        except aiohttp.client_exceptions.ClientResponseError as e:
            retries -= 1
            await asyncio.sleep(back_off)
            continue

async def main():
    async with aiohttp.ClientSession() as session:
        attendee_urls = get_urls('attendee') # returns list of URLs to call asynchronously in get_data()
        attendee_data = await asyncio.gather(*[get_data(session, attendee_url) for attendee_url in attendee_urls])
        return attendee_data

if __name__ == '__main__':
    data = asyncio.run(main())

Вопрос : Как мне ограничить вызовы aiohttp, чтобы они оставались ниже порогового значения 100 вызовов / минут, не делая 403 запроса на возврат? Я пробовал следующие модули, и ни один из них, похоже, ничего не делал: ratelimiter, ratelimit и asyncio-throttle.

Цель : сделать 100 асинхронных c вызовов в минуту, но при необходимости откат и повторная попытка (403: превышен лимит вызовов).

...