简单的Ruby速率限制

时间:2018-04-06 23:16:51

标签: ruby mutex rate rate-limiting

我正在尝试使用数组构建一个非常简单的速率限制算法。

例如,让我们使用以下速率限制作为示例"每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代码?

1 个答案:

答案 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