Как ограничить скорость запросов к веб-сервисам в Python? - PullRequest
9 голосов
/ 30 декабря 2008

Я работаю над библиотекой Python, которая взаимодействует с API веб-службы. Как и многие веб-сервисы, с которыми я сталкивался, этот запрашивает ограничение скорости запросов. Я хотел бы предоставить необязательный параметр limit для экземпляра класса, который, если он предоставляется, будет удерживать исходящие запросы до тех пор, пока не пройдет указанное количество секунд.

Я понимаю, что общий сценарий таков: экземпляр класса делает запрос через метод. Когда это происходит, метод генерирует некоторый сигнал, который устанавливает переменную блокировки где-то, и запускает таймер обратного отсчета для количества секунд в limit. (По всей вероятности, блокировка - это сам таймер обратного отсчета.) Если в течение этого временного интервала сделан другой запрос, он должен быть поставлен в очередь до тех пор, пока таймер обратного отсчета не достигнет нуля и блокировка не будет снята; в этот момент отправляется самый старый запрос в очереди, таймер обратного отсчета сбрасывается, и блокировка вновь включается.

Это случай для потоков? Есть ли другой подход, которого я не вижу?

Должны ли таймер обратного отсчета и блокировка быть переменными экземпляра или они должны принадлежать классу, чтобы все экземпляры класса содержали запросы?

Кроме того, это, как правило, плохая идея для предоставления функции ограничения скорости в библиотеке? Я полагаю, поскольку по умолчанию обратный отсчет равен нулю, библиотека все еще позволяет разработчикам использовать библиотеку и предоставлять свои собственные схемы ограничения скорости. Однако если разработчикам, использующим сервис, в любом случае потребуется ограничивать скорость запросов, я полагаю, что для библиотеки было бы удобно обеспечить средства ограничения скорости.

Независимо от размещения схемы ограничения скорости в библиотеке или нет, я хочу написать приложение с использованием библиотеки, поэтому предложенные методы пригодятся.

Большое спасибо за ваши предложения!

Chris

Ответы [ 6 ]

7 голосов
/ 30 декабря 2008

Это лучше работает с очередью и диспетчером.

Вы разбили свою обработку на две стороны: источник и отправка . Это могут быть отдельные потоки (или отдельные процессы, если это проще).

Сторона Source создает и ставит в очередь запросы с любой скоростью, которая делает их счастливыми.

Сторона Dispatch делает это.

  1. Получить время начала запроса, с .

  2. Отменяет запрос, обрабатывает запрос через удаленный сервис.

  3. Получить текущее время, t . Сон на скорость - ( т - с ) секунд.

Если вы хотите запустить сторону Source , подключенную напрямую к удаленной службе, вы можете сделать это и обойти ограничение скорости. Это хорошо для внутреннего тестирования с фиктивной версией удаленного сервиса.

Сложной частью этого является создание некоторого представления для каждого запроса, который вы можете поставить в очередь. Поскольку Python Queue будет обрабатывать практически все, вам не нужно много делать.

Если вы используете мультиобработку, вам придется засолить ваших объектов, чтобы поместить их в трубу.

2 голосов
/ 30 декабря 2008

Очередь может быть слишком сложной. Более простое решение - дать вашему классу переменную для времени последнего вызова сервиса. Каждый раз, когда служба вызывается (! 1), установите waitTime на delay - Now + lastcalltime. delay должно быть равно минимально допустимому времени между запросами. Если это число положительное, поспите долго перед тем, как позвонить (! 2). Недостаток / преимущество этого подхода в том, что он обрабатывает запросы веб-службы как синхронные. Преимущество в том, что это нелепо просто и легко реализовать.

  • (! 1): должно произойти сразу после получения ответа от службы внутри оболочки (возможно, в нижней части оболочки).
  • (! 2): должно происходить, когда вызывается оболочка python вокруг веб-службы, в верхней части оболочки.

Решение С. Лотта, конечно, более изящно.

1 голос
/ 21 мая 2018

Не изобретайте велосипед, если он не нужен. Проверьте классную библиотеку ratelimit . Идеально, если вы просто хотите по каким-либо причинам ограничить количество звонков на api отдыха и продолжить свою жизнь.

1 голос
/ 30 декабря 2008

Если ваша библиотека спроектирована синхронной, я бы рекомендовал не применять принудительное ограничение (хотя вы могли бы отслеживать тарифы и, по крайней мере, помогать вызывающей стороне решать, как соблюдать ограничения).

Я использую витой для взаимодействия практически со всем в настоящее время. Это позволяет легко делать такие вещи, имея модель, которая отделяет отправку запроса от обработки ответа. Если вы не хотите, чтобы пользователи API использовали витую, вам, по крайней мере, лучше понять их API для отложенного выполнения.

Например, у меня есть интерфейс Twitter, который проталкивает довольно абсурдное количество запросов от имени пользователей xmpp . Я не ограничиваю скорость, но мне пришлось немного поработать, чтобы предотвратить одновременное выполнение всех запросов.

1 голос
/ 30 декабря 2008

Ваша схема ограничения скорости должна находиться под сильным влиянием соглашений о вызовах базового кода (синхронного или асинхронного), а также того, в какой области (поток, процесс, машина, кластер?) Будет работать это ограничение скорости.

Я бы предложил сохранить все переменные в экземпляре, чтобы вы могли легко реализовать несколько периодов / уровней контроля.

Наконец, похоже, что вы хотите быть компонентом промежуточного программного обеспечения. Не пытайтесь быть приложением и создавать темы самостоятельно. Просто блокируйте / спите, если вы работаете синхронно, и используйте платформу асинхронной диспетчеризации, если вам звонит один из них.

0 голосов
/ 31 декабря 2008

ТАК Я предполагаю что-то простое, как время импорта time.sleep (2) не будет работать в течение 2 секунд ожидания между запросами

...