simple_throttle 1.0.5 → 1.0.7

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
  SHA256:
3
- metadata.gz: 30c315dd33f7e175c0e74b4dfd8344e889d7e856c96c786b87ebac29d07fcc3a
4
- data.tar.gz: acfb600e437eb125b9bf279dd95315ce7fa40612f836f887003b360ae2aacceb
3
+ metadata.gz: 4bf38f023dce00a87b27e9b2f39d0519a8dbb4abd90b549697be21ed6792bd7f
4
+ data.tar.gz: 35023bd729899add113084518e63f8ee6975bf71c7a5b12fc0ceb64924ccd207
5
5
  SHA512:
6
- metadata.gz: 89d1b64043ee7f6460be93bb12ac50728e31ede360bcaa68191cb84087d50fe7db4386d8d24eba380c37a9426df78cb26c0685da75d7f6610e244e332be2821c
7
- data.tar.gz: 47598bdce624ab1effbefbfc36d8860f3e017a7ecb2213cdd46d8c67e681583df62bdaf1270f77f6d4e83a88de0c0222c92c3a141fb9bfc3340cbee3bf0914a3
6
+ metadata.gz: dfab9a31ebc150ceb5f6b8833efc670357eefa790e60b33156607f7d72155566c300c454fc58368cae15936b8152f2c47e5ed83875ca3b8e0f58f9219d03d5e1
7
+ data.tar.gz: 4a3bd5605206b8b1e93bcc527c7d3f2dbf22590f23e390c4cb5c75ba7ac3cbe2fef885adffb62006fed54f310eea5804e10c6f319c81c45c8832971d36818718
data/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 1.0.7
8
+
9
+ ## Fixed
10
+ - Fixed peek method to return the correct value rather than the raw value from Redis.
11
+
12
+ ### Changed
13
+ - Updated repository location and gem owners
14
+
15
+ ## 1.0.6
16
+
17
+ ### Added
18
+ - Add support for `pause_to_recover` flag on throttles to force calls to the throttle to fail until the process calling them has paused temporarily.
19
+
7
20
  ## 1.0.5
8
21
 
9
22
  ### Added
data/MIT_LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2016 WHI, Inc.
1
+ Copyright (c) 2016 Brian Durand
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
- [![Maintainability](https://api.codeclimate.com/v1/badges/0535eef45908cc64b740/maintainability)](https://codeclimate.com/github/weheartit/simple_throttle/maintainability)
2
1
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
3
2
 
4
- This gem provides a very simple throttling mechanism backed by redis for limiting access to a resource. The throttle can be thought of as a limit on the number of calls in a set time frame (i.e. 100 calls per hour). These
3
+ This gem provides a very simple throttling mechanism backed by Redis for limiting access to a resource. The throttle can be thought of as a limit on the number of calls in a set time frame (i.e. 100 calls per hour).
5
4
 
6
5
  ## Usage
7
6
 
@@ -38,7 +37,33 @@ Calling `allowed!` will return `true` if the throttle limit has not yet been rea
38
37
 
39
38
  The throttle data is kept in redis as a list of timestamps and will be auto expired if it falls out of use. The thottles time windows are rolling time windows and more calls will be allowed as soon as possible. So, if you have a throttle of, 100 requests per hour, and the throttle kicks in, you will be able to make the next throttled call one hour after the first call being tracked, not one hour after the last call.
40
39
 
41
- Redis server 2.6 or greater is required.
40
+ ### Pause to recover option
41
+
42
+ Throttles can also specify a `pause_to_recover` option set when they are created. When this flag is set, once a throttle check fails, it will continue to fail until the rate at which it is called drops below the maximum rate allowed by the throttle. This is designed for use where you want to detect run away processes constantly hitting a service. Without this set, the process would be able to utilize the resource up to the set limit. With it set, the process would need to pause temporarily to succeed again.
43
+
44
+ For example, if you have a throttle that allows 10 calls per 60 seconds, then a process hitting every second will succeed 10 times per minute. A similar throttle with the `pause_to_recover` option set, would only succeed on the first 10 calls. After that, it will continue to fail until the rate at which it is called drops below the maximum rate of the throttle (i.e. once every 6 seconds).
45
+
46
+ ```ruby
47
+ throttle_1 = SimpleThrottle.new("t1", limit: 10, ttl: 60)
48
+ throttle_2 = SimpleThrottle.new("t2", limit: 10, ttl: 60, pause_to_recover: true)
49
+
50
+ loop do
51
+ if throttle_1.allowed!
52
+ # This will be called 10 times every minute.
53
+ do_thing_1
54
+ end
55
+
56
+ if throttle_2.allowed!
57
+ # This will only be called 10 times in total because the throttle is never
58
+ # given a chance to recover.
59
+ do_thing_2
60
+ end
61
+ end
62
+ ```
63
+
64
+ ### Redis requirement
65
+
66
+ Redis server 2.6 or greater is required for this code.
42
67
 
43
68
  ## Installation
44
69
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.5
1
+ 1.0.7
@@ -16,6 +16,7 @@ class SimpleThrottle
16
16
  local ttl = tonumber(ARGV[2])
17
17
  local now = ARGV[3]
18
18
  local push = tonumber(ARGV[4])
19
+ local pause_to_recover = tonumber(ARGV[5])
19
20
 
20
21
  local size = redis.call('llen', list_key)
21
22
  if size >= limit then
@@ -30,7 +31,7 @@ class SimpleThrottle
30
31
  end
31
32
  end
32
33
 
33
- if push > 0 and size < limit then
34
+ if push > 0 and (size < limit or (size == limit and pause_to_recover > 0)) then
34
35
  redis.call('rpush', list_key, now)
35
36
  redis.call('pexpire', list_key, ttl)
36
37
  end
@@ -48,12 +49,15 @@ class SimpleThrottle
48
49
  # @param name [String] unique name for the throttle
49
50
  # @param ttl [Numeric] number of seconds that the throttle will remain active
50
51
  # @param limit [Integer] number of allowed requests within the throttle ttl
52
+ # @param pause_to_recover [Boolean] require processes calling the throttle
53
+ # to pause at least temporarily before freeing up the throttle. If this is true,
54
+ # then a throttle called constantly with no pauses will never free up.
51
55
  # @param redis [Redis, Proc] Redis instance to use or a Proc that yields a Redos instance
52
56
  # @return [void]
53
- def add(name, ttl:, limit:, redis: nil)
57
+ def add(name, ttl:, limit:, pause_to_recover: false, redis: nil)
54
58
  @lock.synchronize do
55
59
  @throttles ||= {}
56
- @throttles[name.to_s] = new(name, limit: limit, ttl: ttl, redis: redis)
60
+ @throttles[name.to_s] = new(name, limit: limit, ttl: ttl, pause_to_recover: pause_to_recover, redis: redis)
57
61
  end
58
62
  end
59
63
 
@@ -120,12 +124,16 @@ class SimpleThrottle
120
124
  # @param name [String] unique name for the throttle
121
125
  # @param ttl [Numeric] number of seconds that the throttle will remain active
122
126
  # @param limit [Integer] number of allowed requests within the throttle ttl
127
+ # @param pause_to_recover [Boolean] require processes calling the throttle
128
+ # to pause at least temporarily before freeing up the throttle. If this is true,
129
+ # then a throttle called constantly with no pauses will never free up.
123
130
  # @param redis [Redis, Proc] Redis instance to use or a Proc that yields a Redos instance
124
- def initialize(name, ttl:, limit:, redis: nil)
131
+ def initialize(name, ttl:, limit:, pause_to_recover: false, redis: nil)
125
132
  @name = name.to_s
126
133
  @name = name.dup.freeze unless name.frozen?
127
134
  @limit = limit.to_i
128
135
  @ttl = ttl.to_f
136
+ @pause_to_recover = !!pause_to_recover
129
137
  @redis = redis
130
138
  end
131
139
 
@@ -149,7 +157,9 @@ class SimpleThrottle
149
157
  #
150
158
  # @return [Integer]
151
159
  def peek
152
- current_size(false)
160
+ timestamps = redis_client.lrange(redis_key, 0, -1).collect(&:to_i)
161
+ min_timestamp = ((Time.now.to_f - ttl) * 1000).ceil
162
+ timestamps.count { |t| t > min_timestamp }
153
163
  end
154
164
 
155
165
  # Returns when the next resource call should be allowed. Note that this doesn't guarantee that
@@ -182,9 +192,10 @@ class SimpleThrottle
182
192
  # If push is set to true then a new item will be added to the list.
183
193
  def current_size(push)
184
194
  push_arg = (push ? 1 : 0)
195
+ pause_to_recover_arg = (@pause_to_recover ? 1 : 0)
185
196
  time_ms = (Time.now.to_f * 1000).round
186
197
  ttl_ms = (ttl * 1000).ceil
187
- self.class.send(:execute_lua_script, redis: redis_client, keys: [redis_key], args: [limit, ttl_ms, time_ms, push_arg])
198
+ self.class.send(:execute_lua_script, redis: redis_client, keys: [redis_key], args: [limit, ttl_ms, time_ms, push_arg, pause_to_recover_arg])
188
199
  end
189
200
 
190
201
  def redis_key
@@ -1,11 +1,11 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "simple_throttle"
3
3
  spec.version = File.read(File.expand_path("../VERSION", __FILE__)).strip
4
- spec.authors = ["We Heart It", "Brian Durand"]
5
- spec.email = ["dev@weheartit.com", "bbdurand@gmail.com"]
4
+ spec.authors = ["Brian Durand"]
5
+ spec.email = ["bbdurand@gmail.com"]
6
6
 
7
7
  spec.summary = "Simple redis backed throttling mechanism to limit access to a resource"
8
- spec.homepage = "https://github.com/weheartit/simple_throttle"
8
+ spec.homepage = "https://github.com/bdurand/simple_throttle"
9
9
  spec.license = "MIT"
10
10
 
11
11
  # Specify which files should be added to the gem when it is released.
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_throttle
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
- - We Heart It
8
7
  - Brian Durand
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2023-03-04 00:00:00.000000000 Z
11
+ date: 2023-03-31 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: redis
@@ -41,7 +40,6 @@ dependencies:
41
40
  version: '0'
42
41
  description:
43
42
  email:
44
- - dev@weheartit.com
45
43
  - bbdurand@gmail.com
46
44
  executables: []
47
45
  extensions: []
@@ -53,7 +51,7 @@ files:
53
51
  - VERSION
54
52
  - lib/simple_throttle.rb
55
53
  - simple_throttle.gemspec
56
- homepage: https://github.com/weheartit/simple_throttle
54
+ homepage: https://github.com/bdurand/simple_throttle
57
55
  licenses:
58
56
  - MIT
59
57
  metadata: {}