Первым шагом, который я предпринял, было создание объекта, который может распределять максимум n монет каждые t мс.
import time
class CoinsDistribution:
"""Object that distribute a maximum of maxCoins every timeLimit ms"""
def __init__(self, maxCoins, timeLimit):
self.maxCoins = maxCoins
self.timeLimit = timeLimit
self.coin = maxCoins
self.time = time.perf_counter()
def getCoin(self):
if self.coin <= 0 and not self.restock():
return False
self.coin -= 1
return True
def restock(self):
t = time.perf_counter()
if (t - self.time) * 1000 < self.timeLimit:
return False
self.coin = self.maxCoins
self.time = t
return True
Теперь нам нужен способ заставить функцию вызываться только если они могутполучить монетуДля этого мы можем написать функцию декоратора, которую мы могли бы использовать следующим образом:
@limitCalls(callLimit=1, timeLimit=1000)
def uniqFunctionRequestingServer1():
return 'response from s1'
Но иногда несколько функций вызывают один и тот же сервер, поэтому мы хотим, чтобы они получали монеты из одного и того же объекта CoinsDistribution.,Поэтому другое использование декоратора было бы путем предоставления объекта CoinsDistribution:
server_2_limit = CoinsDistribution(3, 1000)
@limitCalls(server_2_limit)
def sendRequestToServer2():
return 'it worked !!'
@limitCalls(server_2_limit)
def sendAnOtherRequestToServer2():
return 'it worked too !!'
Теперь нам нужно создать декоратор, для создания нового объекта может потребоваться либо объект CoinsDistribution, либо достаточно данных.
import functools
def limitCalls(obj=None, *, callLimit=100, timeLimit=1000):
if obj is None:
obj = CoinsDistribution(callLimit, timeLimit)
def limit_decorator(func):
@functools.wraps(func)
def limit_wrapper(*args, **kwargs):
if obj.getCoin():
return func(*args, **kwargs)
return 'limit reached, please wait'
return limit_wrapper
return limit_decorator
И готово!Теперь вы можете ограничить количество вызовов любого API, который вы используете, и вы можете создать словарь для отслеживания ваших объектов CoinsDistribution, если вам приходится управлять многими из них (для разных конечных точек API или для разных API).
Примечание: здесь я решил вернуть сообщение об ошибке, если нет доступных монет.Вы должны адаптировать это поведение к вашим потребностям.