我正在尝试使用数组构建一个非常简单的速率限制算法。
例如,让我们使用以下速率限制作为示例"每5分钟发出5次请求"
我有一个存储时间戳列表的数组(每个元素都是Time.now
),并在调用API时添加到数组中(假设它在速率限制之下)
我在这里也使用了Mutex,因此不同的线程既可以共享timestamp
资源,也可以确保没有竞争条件发生。
但是,我希望这个阵列可以自我清理。如果数组中有5个(或更多)元素,并且其中一个或多个元素在5分钟间隔之外,它将自动删除此条目。
这就是我被困住的地方。
我有以下代码: def初始化(最大,间隔) @ max,@ interval = max,interval @m = Mutex.new @timestamp = [] 端
def validate_rate
@m.synchronize do
if @timestamp.count > @max && self.is_first_ts_expired
@timestamp.shift
if self.rate_count < @max
@timestamp << Time.now
return false
else
return true
end
end
end
end
def is_first_ts_expired
return false if @@timestamp[@name].first.nil? # no logged entries = no expired timestamps
return @@timestamp[@name].first <= Time.now - @interval
end
# Gets the number of requests that are under the allowed interval
def rate_count
count = 0
@timestamp.each { |x|
if x >= Time.now - @interval
count += 1
end
}
count
end
以下是如何调用这个简单的类。 rl.validate_rate
如果超出费率限制,则会返回true
,如果超出限额,则返回false。理想情况下,当timestamp
数组大于max
变量时,它会自动清理它。
rl = RateLimit.new(5, 5.minutes)
raise RateLimitException unless rl.validate_rate do
# stuff
end
我很好奇我在哪里清理&#34;清理&#34;在正确的地方调用is_first_ts_expired
代码?
答案 0 :(得分:1)
我认为这是一种完全有效的方法。
两个快速说明:
1)当你的元素数量少于最大数量时,你似乎只允许插入数组:
if rate_count < @max
@timestamp << Time.now
return true
else
return false
end
但是,当数量超过数组中允许的元素数量时,您还只清除过期的元素:
if @timestamp.count > max && is_first_ts_expired
@timestamp.shift
我认为为了使其正常工作,您需要在检查是否应清除数组中的元素时删除第一个条件。它看起来像这样:
if is_first_ts_expired
@timestamp.shift
2)您只需在此处清除阵列中的一个项目:
if is_first_ts_expired
@timestamp.shift
为了使此解决方案更加强大,您可能希望将if
替换为while
,以便清除多个过期的项目。例如:
while is_first_ts_expired do
@timestamp.shift
end
根据以下评论更新:
如果时间戳已全部到期,您可能会浏览所有时间戳,那么您需要稍微修改is_first_ts_expired
以处理空timestamp
数组。像这样:
def is_first_ts_expired
current_ts = @timestamp.first
current_ts && current_ts <= Time.now - @interval
end