Class: Ratelimitcop

Inherits:
Object
  • Object
show all
Defined in:
lib/ratelimitcop.rb,
lib/ratelimitcop/version.rb

Constant Summary collapse

VERSION =
'1.1.0'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, threshold:, interval:, redis: {}, options: {}) ⇒ Ratelimitcop

Returns a new instance of Ratelimitcop.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/ratelimitcop.rb', line 9

def initialize(name:, threshold:, interval:, redis: {}, options: {})
  @name = name
  @threshold = threshold
  @interval = interval
  @bucket_interval = options[:bucket_interval] ||= 5
  @bucket_time_span = options[:bucket_time_span] ||= 600
  @bucket_span = options[:bucket_span] ||= @bucket_interval

  raise InvalidBucketConfigError if @bucket_interval > @bucket_time_span || @bucket_interval < @bucket_span

  @redis ||= Redis::Namespace.new(:limiter, redis: Redis.new(redis))

  @all_buckets_count = (@bucket_time_span / @bucket_span).floor
  @sliding_window_buckets_count = (@bucket_interval.to_f / @bucket_span).floor
end

Instance Attribute Details

#intervalObject (readonly)

Returns the value of attribute interval.



7
8
9
# File 'lib/ratelimitcop.rb', line 7

def interval
  @interval
end

#nameObject (readonly)

Returns the value of attribute name.



7
8
9
# File 'lib/ratelimitcop.rb', line 7

def name
  @name
end

#thresholdObject (readonly)

Returns the value of attribute threshold.



7
8
9
# File 'lib/ratelimitcop.rb', line 7

def threshold
  @threshold
end

Instance Method Details

#add(count: 1) ⇒ Object



25
26
27
28
29
30
31
32
33
34
# File 'lib/ratelimitcop.rb', line 25

def add(count: 1)
  key = [@name, bucket_index].join(':')

  @redis.multi do
    @redis.incrby(key, count)
    @redis.expire(key, @interval)
  end

  nil
end

#countObject



36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/ratelimitcop.rb', line 36

def count
  current_bucket_index = bucket_index

  bucket_indices = @sliding_window_buckets_count.times.map do |i|
    (current_bucket_index - i) % @all_buckets_count
  end

  @redis.multi do
    bucket_indices.map do |i|
      key = [@name, i].join(':')
      @redis.get(key)
    end
  end.map(&:to_i).sum
end

#exceeded?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/ratelimitcop.rb', line 63

def exceeded?
  count >= @threshold
end

#exec_within_thresholdObject



58
59
60
61
# File 'lib/ratelimitcop.rb', line 58

def exec_within_threshold
  sleep @bucket_span while exceeded?
  yield
end

#execute(&block) ⇒ Object



51
52
53
54
55
56
# File 'lib/ratelimitcop.rb', line 51

def execute(&block)
  add
  exec_within_threshold do
    block.call
  end
end