ограничение скорости вызова функции в рельсах на пользователя - PullRequest
9 голосов
/ 22 июля 2011

У кого-нибудь есть идеи, как мне поступить? Сложно найти информацию в Интернете. Лучшее, что я нашел, - это драгоценность curbit it, но я могу думать только о том, как реализовать это приложение.

Ответы [ 2 ]

8 голосов
/ 22 июля 2011

Может обрабатываться: 1) веб-сервером 2) стоечным приложением. Все зависит от того, что вам нужно. Мы используем встроенную функциональность nginx для ограничения запросов API:

     limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
     limit_req zone=one burst=2;

Другое решение - рычаг-рычаг .

Это промежуточное программное обеспечение Rack, которое предоставляет логику для ограничения скорости входящих HTTP-запросов к приложениям Rack. Вы можете использовать Rack :: Throttle с любым веб-фреймворком Ruby, основанным на Rack, в том числе с Ruby on Rails 3.0 и с Sinatra.

2 голосов
/ 14 января 2012

Вот пример того, как это может быть реализовано с использованием Redis и временных меток. Вы бы включили этот модуль в user.rb, а затем можете позвонить user.allowed_to?(:reveal_email)

# Lets you limit the number of actions a user can take per time period
# Keeps an integer timestamp with some buffer in the past and each action increments the timestamp
# If the counter exceeds Time.now the action is disallowed and the user must wait for some time to pass.

module UserRateLimiting

  class RateLimit < Struct.new(:max, :per)
    def minimum
      Time.now.to_i - (step_size * max)
    end

    def step_size
      seconds = case per
      when :month  then 18144000 # 60 * 60 * 24 * 7 * 30
      when :week   then 604800   # 60 * 60 * 24 * 7
      when :day    then 86400    # 60 * 60 * 24
      when :hour   then 3600     # 60 * 60
      when :minute then 60
      else raise 'invalid per param (day, hour, etc)'
      end
      seconds / max
    end
  end

  LIMITS = {
    :reveal_email => RateLimit.new(200, :day)
    # add new rate limits here...
  }

  def allowed_to? action
    inc_counter(action) < Time.now.to_i
  end

  private

  def inc_counter action
    rl = LIMITS[action]
    raise "couldn't find that action" if rl.nil?
    val = REDIS_COUNTERS.incrby redis_key(action), rl.step_size
    if val < rl.minimum
      val = REDIS_COUNTERS.set redis_key(action), rl.minimum
    end
    val.to_i
  end

  def redis_key action
    "rate_limit_#{action}_for_user_#{self.id}"
  end

end
...