ruby-limiter 1.0.0 → 2.1.0

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
- SHA1:
3
- metadata.gz: 17d71e42e079a0ce7f9b5c9a093e742976998db2
4
- data.tar.gz: 1fc5d17c9e2abf2034deebb98f8da7179bc49701
2
+ SHA256:
3
+ metadata.gz: 144e27e5e203e66c7d753c3da5bce267a514de2f32be74849e96104d6450efe6
4
+ data.tar.gz: 6ec690da1476b519f6cbb6b22ba921b2c8006db09a706553304c0077a692e553
5
5
  SHA512:
6
- metadata.gz: '0618773b6259592f784ec8e6d982e8772984757319bba95e83a4a8a5706d5f6732f90514774783f8fec51d2a1b593e3c8f74cccbdf5d3755484227b8f0a3f376'
7
- data.tar.gz: e70732cd382c742a3f33674c2ee4392d38b322879fa8afdc21a3b9b1fb62107ced1b2fe4487a2de164c9f0d99d42540af8f133e8def0be2b0484da3597d06a68
6
+ metadata.gz: e4568e49199cc0a518439c808bc28e3281bdc44994495a0bee5e379c40c0de29bf45deee1e55d16d4f80df86424f26411c2f8b0fe13af605d18f8eb4b08c61db
7
+ data.tar.gz: 385abafc6d5e638829c0cd278a311b1d997a5c2b41e1010ae4b46cac5772498906f5254ab44777d353f36ef7ca228ce134ee2d6b91ceae4310384c4d9d5809e7
data/.rubocop.yml CHANGED
@@ -2,4 +2,4 @@ inherit_from:
2
2
  - https://shopify.github.io/ruby-style-guide/rubocop.yml
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.3
5
+ TargetRubyVersion: 2.7
data/.travis.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.3
5
- - 2.4
6
- - 2.5
4
+ - 2.6
5
+ - 2.7
6
+ - 3.0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v2.1.0
4
+
5
+ - add support to call a block when limiting takes place
6
+
7
+ ## v2.0.1
8
+
9
+ - eliminate kwarg warning in ruby 2.7 (while still supporting 2.6)
10
+
11
+ ## v2.0.0
12
+
13
+ - end support for ruby 2.3/2.4/2.5
14
+ - test on ruby 2.6/2.7/3.0 (using ruby 2.7 for development)
15
+
16
+ ## v1.1.0
17
+
18
+ - using Process.clock_gettime(Process::CLOCK_MONOTONIC) instead of Time.now for improved accuracy
19
+
20
+ ## v1.0.2
21
+
22
+ - DOCFIX: fix name of gem in README
23
+ - BUGFIX: add ruby-limiter.rb so that it works better with bundler
24
+
25
+ ## v1.0.1
26
+
27
+ - BUGFIX: support arguments for throttled methods
28
+
3
29
  ## v1.0.0
4
30
 
5
31
  - initial release
data/README.md CHANGED
@@ -7,7 +7,7 @@ This gem implements a simple mechanism to throttle or rate-limit operations in R
7
7
  Add this line to your application's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'limiter'
10
+ gem 'ruby-limiter'
11
11
  ```
12
12
 
13
13
  And then execute:
@@ -16,13 +16,13 @@ And then execute:
16
16
 
17
17
  Or install it yourself as:
18
18
 
19
- $ gem install limiter
19
+ $ gem install ruby-limiter
20
20
 
21
21
  ## Usage
22
22
 
23
23
  ### Basic Usage
24
24
 
25
- To rate limit calling an instance method, a mixin is provided. Simply specify the method to me limited, and the maximum
25
+ To rate limit calling an instance method, a mixin is provided. Simply specify the method to be limited, and the maximum
26
26
  rate that the method can be called. This rate is (by default) a number of requests per minute.
27
27
 
28
28
  ``` ruby
@@ -46,7 +46,10 @@ class Widget
46
46
 
47
47
  # limit the rate we can call tick to 5 times per second
48
48
  # when the rate has been exceeded, a call to tick will block until the rate limit would not be exceeded
49
- limit_method :tick, rate: 5, interval: 1
49
+ # and the provided block will be executed
50
+ limit_method(:tick, rate: 5, interval: 1) do
51
+ puts 'Limit reached'
52
+ end
50
53
 
51
54
  ...
52
55
  end
@@ -55,13 +58,16 @@ end
55
58
  ### Advanced Usage
56
59
 
57
60
  In cases where the mixin is not appropriate the `RateQueue` class can be used directly. As in the mixin examples above,
58
- the `interval` parameter is optional (and defaults to 1 minute).
61
+ the `interval` parameter is optional (and defaults to 1 minute). It is also possible
62
+ to provide the block to `RateQueue`, which will be executed on each limit hit (useful for metrics).
59
63
 
60
64
  ``` ruby
61
65
  class Widget
62
66
  def initialize
63
67
  # create a rate-limited queue which allows 10000 operations per hour
64
- @queue = RateQueue.new(10000, interval: 3600)
68
+ @queue = Limiter::RateQueue.new(10000, interval: 3600) do
69
+ puts "Hit the limit, waiting"
70
+ end
65
71
  end
66
72
 
67
73
  def tick
data/Rakefile CHANGED
@@ -7,6 +7,7 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.libs << "test"
8
8
  t.libs << "lib"
9
9
  t.test_files = FileList["test/**/*_test.rb"]
10
+ t.warning = true
10
11
  end
11
12
 
12
- task default: :test
13
+ task default: :test
data/dev.yml CHANGED
@@ -3,7 +3,7 @@
3
3
  name: limiter
4
4
 
5
5
  up:
6
- - ruby: 2.4.4
6
+ - ruby: 2.7.3
7
7
  - bundler
8
8
 
9
9
  commands:
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require 'forwardable'
5
+
6
+ module Limiter
7
+ class Clock
8
+ include Singleton
9
+
10
+ extend SingleForwardable
11
+ def_single_delegators :instance, :sleep, :time
12
+
13
+ def sleep(interval)
14
+ Kernel.sleep(interval)
15
+ end
16
+
17
+ def time
18
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
19
+ end
20
+ end
21
+ end
data/lib/limiter/mixin.rb CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  module Limiter
4
4
  module Mixin
5
- def limit_method(method, rate:, interval: 60)
6
- queue = RateQueue.new(rate, interval: interval)
5
+ def limit_method(method, rate:, interval: 60, &b)
6
+ queue = RateQueue.new(rate, interval: interval, &b)
7
7
 
8
8
  mixin = Module.new do
9
- define_method(method) do
9
+ define_method(method) do |*args, **options, &blk|
10
10
  queue.shift
11
- super()
11
+ options.empty? ? super(*args, &blk) : super(*args, **options, &blk)
12
12
  end
13
13
  end
14
14
 
@@ -2,15 +2,16 @@
2
2
 
3
3
  module Limiter
4
4
  class RateQueue
5
- EPOCH = Time.at(0)
5
+ EPOCH = 0.0
6
6
 
7
- def initialize(size, interval: 60)
7
+ def initialize(size, interval: 60, &blk)
8
8
  @size = size
9
9
  @interval = interval
10
10
 
11
11
  @ring = Array.new(size, EPOCH)
12
12
  @head = 0
13
13
  @mutex = Mutex.new
14
+ @blk = blk
14
15
  end
15
16
 
16
17
  def shift
@@ -21,7 +22,7 @@ module Limiter
21
22
 
22
23
  sleep_until(time + @interval)
23
24
 
24
- @ring[@head] = Time.now
25
+ @ring[@head] = clock.time
25
26
  @head = (@head + 1) % @size
26
27
  end
27
28
 
@@ -31,9 +32,14 @@ module Limiter
31
32
  private
32
33
 
33
34
  def sleep_until(time)
34
- interval = time - Time.now
35
+ interval = time - clock.time
35
36
  return unless interval.positive?
36
- sleep(interval)
37
+ @blk.call if @blk
38
+ clock.sleep(interval)
39
+ end
40
+
41
+ def clock
42
+ Clock
37
43
  end
38
44
  end
39
45
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Limiter
4
- VERSION = '1.0.0'
4
+ VERSION = '2.1.0'
5
5
  end
data/lib/limiter.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'limiter/clock'
3
4
  require 'limiter/mixin'
4
5
  require 'limiter/rate_queue'
5
6
  require 'limiter/version'
@@ -0,0 +1 @@
1
+ require 'limiter'
data/limiter.gemspec CHANGED
@@ -13,6 +13,13 @@ Gem::Specification.new do |spec|
13
13
  spec.summary = 'Simple Ruby rate limiting mechanism.'
14
14
  spec.homepage = 'https://github.com/Shopify/limiter'
15
15
  spec.license = 'MIT'
16
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
17
+
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
22
+ end
16
23
 
17
24
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
25
  f.match(%r{^(test|spec|features)/})
@@ -21,9 +28,10 @@ Gem::Specification.new do |spec|
21
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
29
  spec.require_paths = %w(lib)
23
30
 
24
- spec.add_development_dependency 'bundler', '~> 1.15'
31
+ spec.add_development_dependency 'bundler'
25
32
  spec.add_development_dependency 'minitest', '~> 5.0'
33
+ spec.add_development_dependency 'minitest-focus', '~> 1.3'
34
+ spec.add_development_dependency 'mocha', '~> 1.11'
26
35
  spec.add_development_dependency 'rake', '~> 10.0'
27
36
  spec.add_development_dependency 'rubocop', '~> 0.56'
28
- spec.add_development_dependency 'timecop', '~> 0.8.0'
29
37
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-limiter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - S. Brent Faulkner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-06 00:00:00.000000000 Z
11
+ date: 2021-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.15'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.15'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -39,47 +39,61 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '5.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: minitest-focus
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '1.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '1.3'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubocop
56
+ name: mocha
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.56'
61
+ version: '1.11'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.56'
68
+ version: '1.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: timecop
84
+ name: rubocop
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: 0.8.0
89
+ version: '0.56'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: 0.8.0
96
+ version: '0.56'
83
97
  description:
84
98
  email:
85
99
  - brent.faulkner@shopify.com
@@ -100,14 +114,17 @@ files:
100
114
  - bin/setup
101
115
  - dev.yml
102
116
  - lib/limiter.rb
117
+ - lib/limiter/clock.rb
103
118
  - lib/limiter/mixin.rb
104
119
  - lib/limiter/rate_queue.rb
105
120
  - lib/limiter/version.rb
121
+ - lib/ruby-limiter.rb
106
122
  - limiter.gemspec
107
123
  homepage: https://github.com/Shopify/limiter
108
124
  licenses:
109
125
  - MIT
110
- metadata: {}
126
+ metadata:
127
+ allowed_push_host: https://rubygems.org
111
128
  post_install_message:
112
129
  rdoc_options: []
113
130
  require_paths:
@@ -116,15 +133,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
133
  requirements:
117
134
  - - ">="
118
135
  - !ruby/object:Gem::Version
119
- version: '0'
136
+ version: 2.6.0
120
137
  required_rubygems_version: !ruby/object:Gem::Requirement
121
138
  requirements:
122
139
  - - ">="
123
140
  - !ruby/object:Gem::Version
124
141
  version: '0'
125
142
  requirements: []
126
- rubyforge_project:
127
- rubygems_version: 2.6.14
143
+ rubygems_version: 3.2.20
128
144
  signing_key:
129
145
  specification_version: 4
130
146
  summary: Simple Ruby rate limiting mechanism.