ruby-limiter 1.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.