ruby_rolling_rate_limiter 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7a4d27689f6f0095e817f2ddc39e345e7a0fdb09
4
- data.tar.gz: 974182baa28ce3742660d2cc5996c40fbe19c749
3
+ metadata.gz: 707ecff1e33f4f609cc8399cdebab57ad206daca
4
+ data.tar.gz: 89273199718232705e954c41decdaa1923e10a98
5
5
  SHA512:
6
- metadata.gz: 81fb38c9de11936c994ab72b05c41b9b6679250327b9e9e17499af7b06c4f3d78d5fb69dd54894139f510e73cada103a3374b0eb1800471b3e0d214f0fe3d7ca
7
- data.tar.gz: 1cb014c36c572ce9022021c37adddb1d9500f85c0f0f76bf0e806ec07ca1a2e1bb7501a99859672ad975430b70336c100f417853877dc484e6b90d7f53290eb3
6
+ metadata.gz: 41bd11d653038fb3008c62e15289a031b3390ea797d8f38bfa1c1a602420ae5ca7c38459bc117e600b35eb2db9bc20b328ff71f82c4c91ae7d00b5bd59491a58
7
+ data.tar.gz: f683ecb68d5c63da9aa0eae3b3d1fd648f89d4ea7517f82ab39edf3cd0eb6c15ab3eacd56ecfbe50e9614ff6bce6274c3189e071b0927499f6ff3abe17a5ce6d
@@ -1,7 +1,7 @@
1
1
  require "ruby_rolling_rate_limiter/version"
2
2
  require "ruby_rolling_rate_limiter/errors"
3
3
  require "redis"
4
- require 'redis-lock'
4
+ require 'redlock'
5
5
  require "date"
6
6
 
7
7
  class RubyRollingRateLimiter
@@ -14,12 +14,13 @@ class RubyRollingRateLimiter
14
14
  @max_calls_per_interval = max_calls_per_interval
15
15
  @min_distance_between_calls_in_seconds = min_distance_between_calls_in_seconds
16
16
  @redis_connection = redis_connection
17
-
18
17
  #Check to ensure args are good.
19
18
  validate_arguments
20
19
 
21
20
  # Check Redis is there
22
21
  check_redis_is_available
22
+ # Setup the Lock Manager
23
+ @lock_manager ||= Redlock::Client.new([redis_connection])
23
24
 
24
25
  end
25
26
 
@@ -42,24 +43,40 @@ class RubyRollingRateLimiter
42
43
 
43
44
  clear_before = now - interval
44
45
  # Begin multi redis
45
- @redis_connection.lock("#{key}-lock") do |lock|
46
- @redis_connection.multi
47
- @redis_connection.zremrangebyscore(key, 0, clear_before.to_s)
48
- @redis_connection.zrange(key, 0, -1)
49
- cur = @redis_connection.exec
46
+ max_retry_counter = 0
47
+ begin
48
+ if max_retry_counter <= 100
49
+ @lock_manager.lock("#{key}-lock", 10000) do |locked|
50
+ if locked
51
+ @redis_connection.multi
52
+ @redis_connection.zremrangebyscore(key, 0, clear_before.to_s)
53
+ @redis_connection.zrange(key, 0, -1)
54
+ cur = @redis_connection.exec
50
55
 
51
- if (cur[1].count <= @max_calls_per_interval) && ((cur[1].count+call_size) <= @max_calls_per_interval) && ((@min_distance_between_calls_in_seconds * 1000 * 1000) && (now - cur[1].last.to_i) > (@min_distance_between_calls_in_seconds * 1000 * 1000))
52
- @redis_connection.multi
53
- @redis_connection.zrange(key, 0, -1)
54
- call_size.times do
55
- @redis_connection.zadd(key, now.to_s, now.to_s)
56
+ if (cur[1].count <= @max_calls_per_interval) && ((cur[1].count+call_size) <= @max_calls_per_interval) && ((@min_distance_between_calls_in_seconds * 1000 * 1000) && (now - cur[1].last.to_i) > (@min_distance_between_calls_in_seconds * 1000 * 1000))
57
+ @redis_connection.multi
58
+ @redis_connection.zrange(key, 0, -1)
59
+ call_size.times do
60
+ @redis_connection.zadd(key, now.to_s, now.to_s)
61
+ end
62
+ @redis_connection.expire(key, @interval_in_seconds)
63
+ results = @redis_connection.exec
64
+ else
65
+ results = [cur[1]]
66
+ end
67
+ else
68
+ raise Errors::LockWaiting, "Could not aquire lock"
69
+ end
56
70
  end
57
- @redis_connection.expire(key, @interval_in_seconds)
58
- results = @redis_connection.exec
59
71
  else
60
- results = [cur[1]]
72
+ raise Errors::MaxRetryReachedOnLockAcquire, "Unable to acquire lock for rate limit after 100 attempts"
61
73
  end
74
+ rescue Errors::LockWaiting
75
+ sleep 0.2
76
+ max_retry_counter +=1
77
+ retry
62
78
  end
79
+
63
80
  if results
64
81
  call_set = results[0]
65
82
  too_many_in_interval = call_set.count >= @max_calls_per_interval
@@ -2,5 +2,7 @@ class RubyRollingRateLimiter
2
2
  module Errors
3
3
  class RedisNotFound < StandardError; end
4
4
  class ArgumentInvalid < StandardError; end
5
+ class LockWaiting < StandardError; end
6
+ class MaxRetryReachedOnLockAcquire < StandardError; end
5
7
  end
6
8
  end
@@ -1,3 +1,3 @@
1
1
  class RubyRollingRateLimiter
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -28,5 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "bump"
29
29
 
30
30
  spec.add_runtime_dependency "redis", "~> 3.2"
31
- spec.add_runtime_dependency "mlanett-redis-lock"
31
+ spec.add_runtime_dependency "redlock", "~> 0.1.5"
32
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_rolling_rate_limiter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karl Kloppenborg
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-04-07 00:00:00.000000000 Z
11
+ date: 2016-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,19 +81,19 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.2'
83
83
  - !ruby/object:Gem::Dependency
84
- name: mlanett-redis-lock
84
+ name: redlock
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 0.1.5
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: 0.1.5
97
97
  description: Often Redis is used for rate limiting purposes. Usually the rate limit
98
98
  packages available count how many times something happens on a certain second or
99
99
  a certain minute. When the clock ticks to the next minute, rate limit counter is