speed_limiter 0.0.1 → 0.2.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
2
  SHA256:
3
- metadata.gz: ee6151563233234c9c453843d4d3d98e8de465905e38e99437caaa6a0e258d6b
4
- data.tar.gz: 9efaa7b0784d79a9a23c77015013519380d20b94645e39e725d390030ad48569
3
+ metadata.gz: b360a3c2df8c37b8ac47eec08222e784ef475966c5938c93f1206e56c2ec353d
4
+ data.tar.gz: 34a890cdbdf74a0fcb25b2140c124ec6f6487ebf2aec4115084fabbc2a437ddd
5
5
  SHA512:
6
- metadata.gz: a9672f7b225e6325589c9bb8fae4cc76ad860024b9fbbcdb6f10edc5d4137ac593b4d6ac5370e6490b1ccc1186b0032bf20d572644ec8177afa783d5603cfe2d
7
- data.tar.gz: 74020c4965b083e2cea5af94a05299455d2ee64060fc008e8fa9b7b5afacae0a587d432925ece9f7efb860388fa15886742d7c5d722751cdb877d6bf31d30110
6
+ metadata.gz: 0ed1f8c6f934e2955b5fd398f6cead553eff69e3e93cb2816a6a3cb41f61fe0848980b0fe1310d17f531ce8f4266de80b0599b7416d1c4d4d8bbda9a61f92c43
7
+ data.tar.gz: 6ef932d30fc72b180b2e968b3f57e75621b15d36b1afc33488cd80a2fa1e0c26802650db1902f97fac29c4294905f12abe17fdb1c99b7200772f77f7c5bab89e
@@ -12,7 +12,7 @@ jobs:
12
12
  timeout-minutes: 10
13
13
 
14
14
  steps:
15
- - uses: actions/checkout@v3
15
+ - uses: actions/checkout@v4
16
16
 
17
17
  - name: Set up Ruby
18
18
  uses: ruby/setup-ruby@v1
@@ -18,27 +18,45 @@ jobs:
18
18
  timeout-minutes: 10
19
19
 
20
20
  strategy:
21
+ max-parallel: 6
21
22
  matrix:
22
- ruby-version: ['3.0', '3.1', '3.2', ruby-head]
23
- redis-version: ['5.0', '6.0', '6.2', '7.0', '7.2', latest]
23
+ set:
24
+ - ruby-version: '3.0'
25
+ redis-version: '7.2'
26
+ - ruby-version: '3.1'
27
+ redis-version: '7.2'
28
+ - ruby-version: '3.2'
29
+ redis-version: '5.0'
30
+ - ruby-version: '3.2'
31
+ redis-version: '6.0'
32
+ - ruby-version: '3.2'
33
+ redis-version: '6.2'
34
+ - ruby-version: '3.2'
35
+ redis-version: '7.0'
36
+ - ruby-version: '3.2'
37
+ redis-version: '7.2'
38
+ - ruby-version: '3.2'
39
+ redis-version: latest
40
+ - ruby-version: ruby-head
41
+ redis-version: '7.2'
24
42
 
25
43
  services:
26
44
  redis:
27
- image: redis:${{ matrix.redis-version }}
45
+ image: redis:${{ matrix.set.redis-version }}
28
46
  ports:
29
47
  - 6379:6379
30
48
 
31
49
  steps:
32
- - uses: actions/checkout@v3
50
+ - uses: actions/checkout@v4
33
51
 
34
- - name: Set up Ruby ${{ matrix.ruby-version }}
52
+ - name: Set up Ruby ${{ matrix.set.ruby-version }}
35
53
  uses: ruby/setup-ruby@v1
36
54
  with:
37
- ruby-version: ${{ matrix.ruby-version }}
55
+ ruby-version: ${{ matrix.set.ruby-version }}
38
56
  bundler-cache: true
39
57
 
40
- - name: Rackup test throttle server
41
- run: bundle exec pumad -C throttle_server/puma.rb throttle_server/config.ru
58
+ - name: Rackup test web server
59
+ run: bundle exec rake throttle_server:start_daemon
42
60
 
43
61
  - name: Run tests
44
62
  run: bundle exec rspec -fd
data/.rubocop.yml CHANGED
@@ -18,3 +18,6 @@ Rspec/MultipleExpectations:
18
18
  Rspec/ExampleLength:
19
19
  Enabled: false
20
20
 
21
+ Metrics/BlockLength:
22
+ Exclude:
23
+ - 'Rakefile'
data/Gemfile CHANGED
@@ -13,6 +13,7 @@ group :development do
13
13
  gem "rack-attack", "~> 6.7"
14
14
  gem "rackup", "~> 2.1"
15
15
  gem "rake"
16
+ gem "retryable"
16
17
  gem "rspec"
17
18
  gem "rubocop"
18
19
  gem "rubocop-rake"
data/README.md CHANGED
@@ -1,12 +1,14 @@
1
- [![lint](https://github.com/seibii/speed_limiter/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/seibii/speed_limiter/actions/workflows/lint.yml) [![test](https://github.com/seibii/speed_limiter/actions/workflows/test.yml/badge.svg)](https://github.com/seibii/speed_limiter/actions/workflows/test.yml) [![Gem Version](https://badge.fury.io/rb/speed_limiter.svg)](https://badge.fury.io/rb/speed_limiter) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
1
+ [![lint](https://github.com/seibii/speed_limiter/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/seibii/speed_limiter/actions/workflows/lint.yml) [![test](https://github.com/seibii/speed_limiter/actions/workflows/test.yml/badge.svg)](https://github.com/seibii/speed_limiter/actions/workflows/test.yml) [![Gem Version](https://badge.fury.io/rb/speed_limiter.svg)](https://badge.fury.io/rb/speed_limiter) [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
2
2
 
3
3
  # SpeedLimiter
4
4
 
5
5
  <img src="README_image.jpg" width="400px" />
6
6
 
7
- This is a Gem for execution limits in multi-process and multi-threaded environments. By using Redis, you can limit execution across multiple processes and threads.
7
+ SpeedLimiter is a gem that limits the number of executions per unit of time.
8
+ By default, it achieves throttling through sleep.
9
+
10
+ You can also use the `on_throttled` event to raise an exception instead of sleeping, or to re-enqueue the task.
8
11
 
9
- It was mainly created to avoid hitting access limits to the API server.
10
12
 
11
13
  ## Installation
12
14
 
@@ -26,19 +28,107 @@ Or install it yourself as:
26
28
 
27
29
  ## Usage
28
30
 
31
+ Limit the number of executions to 10 times per second.
32
+
33
+ ```ruby
34
+ SpeedLimiter.throttle('server_name/method_name', limit: 10, period: 1) do |state|
35
+ puts state #=> <SpeedLimiter::State key=server_name/method_name count=1 ttl=0>
36
+ http.get(path)
37
+ end
38
+
39
+ # or
40
+
41
+ throttle_limit_10_par_sec = SpeedLimiter.throttle('server_name/method_name', limit: 10, period: 1)
42
+
43
+ throttle_limit_10_par_sec.call do |state|
44
+ puts state #=> <SpeedLimiter::State key=server_name/method_name count=1 ttl=0>
45
+ http.get(path)
46
+ end
47
+ ```
48
+
49
+ It returns the result of the block execution.
50
+
51
+ ```ruby
52
+ result = SpeedLimiter.throttle('server_name/method_name', limit: 10, period: 1) do
53
+ http.get(path)
54
+ end
55
+ puts result.code #=> 200
56
+ ```
57
+
58
+ ### on_throttled option
59
+
60
+ Specify the process when the limit is exceeded.
61
+
62
+ ```ruby
63
+ on_throttled = proc { |state| logger.info("limit exceeded #{state.key} #{state.ttl}") }
64
+ SpeedLimiter.throttle('server_name/method_name', limit: 10, period: 1, on_throttled: on_throttled) do
65
+ http.get(path)
66
+ end
67
+ ```
68
+
69
+ Reinitialize the queue instead of sleeping when the limit is reached in ActiveJob.
70
+
71
+ ```ruby
72
+ class CreateSlackChannelJob < ApplicationJob
73
+ def perform(*args)
74
+ on_throttled = proc do |state|
75
+ raise Slack::LimitExceeded, state.ttl if state.ttl > 5
76
+ end
77
+
78
+ SpeedLimiter.throttle("slack", limit: 20, period: 1.minute, on_throttled: on_throttled) do
79
+ create_slack_channel(*args)
80
+ end
81
+ rescue Slack::LimitExceeded => e
82
+ self.class.set(wait: e.ttl).perform_later(*args)
83
+ end
84
+ end
85
+ ```
86
+
87
+ ### retry option
88
+
89
+ To use the `retry:` option, you need to introduce the [Retryable gem](https://github.com/nfedyashev/retryable).
90
+ By specifying the options of the Retryable gem, you can retry when an exception occurs.
91
+
29
92
  ```ruby
30
- # Limit the number of executions to 10 times per second
93
+ # Gemfile
94
+ gem 'retryable'
95
+ ```
96
+
97
+ ```ruby
98
+ SpeedLimiter.throttle('server_name/method_name', limit: 10, period: 1, retry: { tries: 3, on: OpenURI::HTTPError }) do
99
+ http.get(path)
100
+ end
101
+
102
+ # equivalent to
31
103
  SpeedLimiter.throttle('server_name/method_name', limit: 10, period: 1) do
32
- # Do something
104
+ Retryable.retryable(tries: 3, on: OpenURI::HTTPError) do
105
+ http.get(path)
106
+ end
107
+ end
108
+ ```
109
+
110
+ `retry: true` or `retry: {}` is default use of `Retryable.configure`.
111
+
112
+ ```ruby
113
+ SpeedLimiter.throttle('server_name/method_name', limit: 10, period: 1, retry: true) do
114
+ http.get(path)
33
115
  end
34
116
  ```
35
117
 
36
- ### Configuration
118
+ ## Configuration
119
+
120
+ ### Redis configuration
121
+
122
+ Redis can be specified as follows
123
+
124
+ 1. default url `redis://localhost:6379/0`
125
+ 2. `SPEED_LIMITER_REDIS_URL` environment variable
126
+ 3. Configure `SpeedLimiter.configure`
37
127
 
38
128
  ```ruby
39
129
  # config/initializers/speed_limiter.rb
40
130
  SpeedLimiter.configure do |config|
41
- config.redis_url = ENV['SPEED_LIMITER_REDIS_URL'] || 'redis://localhost:6379/2'
131
+ config.redis_url = ENV.fetch('SPEED_LIMITER_REDIS_URL', 'redis://localhost:6379/2')
42
132
  end
43
133
  ```
44
134
 
@@ -51,6 +141,20 @@ SpeedLimiter.configure do |config|
51
141
  end
52
142
  ```
53
143
 
144
+ ### Other configuration defaults
145
+
146
+ ```ruby
147
+ SpeedLimiter.configure do |config|
148
+ config.redis_url = ENV.fetch("SPEED_LIMITER_REDIS_URL", "redis://localhost:6379/0")
149
+ config.redis = nil
150
+ config.no_limit = false # If true, it will not be throttled
151
+ config.prefix = "speed_limiter" # Redis key prefix
152
+ config.on_throttled = nil # Proc to be executed when the limit is exceeded
153
+ end
154
+ ```
155
+
156
+ ### Example
157
+
54
158
  If you do not want to impose a limit in the test environment, please set it as follows.
55
159
 
56
160
  ```ruby
@@ -64,6 +168,24 @@ RSpec.configure do |config|
64
168
  end
65
169
  ```
66
170
 
171
+ If you want to detect the limit in the test environment, please set it as follows.
172
+
173
+ ```ruby
174
+ Rspec.describe do
175
+ around do |example|
176
+ SpeedLimiter.config.on_throttled = proc { |state| raise "limit exceeded #{state.key} #{state.ttl}" }
177
+
178
+ example.run
179
+
180
+ SpeedLimiter.config.on_throttled = nil
181
+ end
182
+
183
+ it do
184
+ expect { over_limit_method }.to raise_error('limit exceeded key_name [\d.]+')
185
+ end
186
+ end
187
+ ```
188
+
67
189
  ## Compatibility
68
190
 
69
191
  SpeedLimiter officially supports the following Ruby implementations and Redis :
@@ -82,11 +204,11 @@ You can also run bin/console for an interactive prompt that will allow you to ex
82
204
 
83
205
  ### rspec
84
206
 
85
- Start a web server and Redis for testing with the following command.
207
+ Start a test web server and Redis for testing with the following command.
86
208
 
87
- ```
88
- $ rake test:throttle_server
89
- $ docker compose up
209
+ ```console
210
+ $ rake throttle_server:start_daemon # or rake throttle_server:start
211
+ $ docker compose up -d
90
212
  ```
91
213
 
92
214
  After that, please run the test with the following command.
data/Rakefile CHANGED
@@ -12,9 +12,33 @@ RuboCop::RakeTask.new
12
12
 
13
13
  task default: :spec
14
14
 
15
- namespace :test do
16
- desc "Run rackup for throttle server daemon"
17
- task :throttle_server do
15
+ namespace :throttle_server do
16
+ desc "Run rackup for Throttle server"
17
+ task :start do
18
18
  system "puma -C throttle_server/puma.rb throttle_server/config.ru"
19
19
  end
20
+
21
+ desc "Run rackup for Throttle server daemon"
22
+ task :start_daemon do
23
+ system "pumad -C throttle_server/puma.rb throttle_server/config.ru"
24
+ end
25
+
26
+ desc "Stop the Throttle server daemon"
27
+ task :stop do
28
+ pid_file = "throttle_server/tmp/puma.pid"
29
+
30
+ if File.exist?(pid_file)
31
+ pid = File.read(pid_file).to_i
32
+ begin
33
+ Process.kill("TERM", pid)
34
+ puts "Throttle server (PID: #{pid}) has been stopped."
35
+ rescue Errno::ESRCH
36
+ puts "Throttle server (PID: #{pid}) not found. It might have already stopped."
37
+ rescue StandardError => e
38
+ puts "Failed to stop Throttle server (PID: #{pid}): #{e.message}"
39
+ end
40
+ else
41
+ puts "PID file not found. Is the Throttle server running?"
42
+ end
43
+ end
20
44
  end
@@ -3,13 +3,14 @@
3
3
  module SpeedLimiter
4
4
  # config model
5
5
  class Config
6
- attr_accessor :redis_url, :redis, :no_limit, :prefix
6
+ attr_accessor :redis_url, :redis, :no_limit, :prefix, :on_throttled
7
7
 
8
8
  def initialize
9
- @redis_url = "redis://localhost:6379/0"
9
+ @redis_url = ENV.fetch("SPEED_LIMITER_REDIS_URL", "redis://localhost:6379/0")
10
10
  @redis = nil
11
11
  @no_limit = false
12
12
  @prefix = "speed_limiter"
13
+ @on_throttled = nil
13
14
  end
14
15
 
15
16
  alias no_limit? no_limit
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpeedLimiter
4
+ # Redis wrapper
5
+ class Redis
6
+ def initialize(redis)
7
+ @redis = redis
8
+ end
9
+ attr_reader :redis
10
+
11
+ def ttl(key)
12
+ redis.pttl(key) / 1000.0
13
+ end
14
+
15
+ def increment(key, period) # rubocop:disable Metrics/MethodLength
16
+ if supports_expire_nx?
17
+ count, ttl = redis.pipelined do |pipeline|
18
+ pipeline.incrby(key, 1)
19
+ pipeline.call(:expire, key, period.to_i, "NX")
20
+ end
21
+ else
22
+ count, ttl = redis.pipelined do |pipeline|
23
+ pipeline.incrby(key, 1)
24
+ pipeline.ttl(key)
25
+ end
26
+ redis.expire(key, period.to_i) if ttl.negative?
27
+ end
28
+
29
+ [count, ttl]
30
+ end
31
+
32
+ private
33
+
34
+ def supports_expire_nx?
35
+ return @supports_expire_nx if defined?(@supports_expire_nx)
36
+
37
+ redis_versions = redis.info("server")["redis_version"]
38
+ @supports_expire_nx = Gem::Version.new(redis_versions) >= Gem::Version.new("7.0.0")
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "speed_limiter/state"
4
+ require "forwardable"
5
+
6
+ module SpeedLimiter
7
+ # Execution status model
8
+ class State
9
+ extend Forwardable
10
+
11
+ # @param params [SpeedLimiter::ThrottleParams]
12
+ # @param count [Integer] current count
13
+ # @param ttl [Float] remaining time to reset
14
+ def initialize(params:, count:, ttl:)
15
+ @params = params
16
+ @count = count
17
+ @ttl = ttl
18
+ end
19
+
20
+ attr_reader :params, :count, :ttl
21
+
22
+ def_delegators(:params, :config, :key, :limit, :period, :on_throttled, :retry)
23
+
24
+ def inspect
25
+ "<#{self.class.name} key=#{key.inspect} count=#{count} ttl=#{ttl}>"
26
+ end
27
+ alias to_s inspect
28
+ end
29
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "speed_limiter/redis"
5
+ require "speed_limiter/throttle_params"
6
+
7
+ module SpeedLimiter
8
+ # with actual throttle limits
9
+ class Throttle
10
+ extend Forwardable
11
+
12
+ # @param key [String, #to_s] Throttle key name
13
+ # @option params [Integer] :limit limit count per period
14
+ # @option params [Integer] :period period time (seconds)
15
+ # @option params [Proc, #call] :on_throttled Block called when limit exceeded, with ttl(Float) and key as argument
16
+ # @option params [true, Hash] :retry Retry options. (see {Retryable.retryable} for details)
17
+ def initialize(key, config:, **params)
18
+ params[:key] = key.to_s
19
+
20
+ @config = config
21
+ @params = ThrottleParams.new(config: config, **params)
22
+ end
23
+ attr_reader :config, :params, :block
24
+
25
+ delegate %i[key redis_key limit period on_throttled create_state] => :params
26
+
27
+ # @yield [state]
28
+ # @yieldparam state [SpeedLimiter::State]
29
+ # @return [any] block return value
30
+ def call(&block)
31
+ if use_retryable?
32
+ Retryable.retryable(**retryable_options) { run_block(&block) }
33
+ else
34
+ run_block(&block)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def use_retryable?
41
+ return false if params.retry == false || params.retry.nil?
42
+
43
+ unless Gem::Specification.find_by_name("retryable")
44
+ raise ArgumentError, "To use the 'retry' option, you need to install the Retryable gem."
45
+ end
46
+
47
+ require "retryable"
48
+ params.retry.is_a?(Hash) || params.retry == true
49
+ end
50
+
51
+ def retryable_options
52
+ return {} if params.retry == true
53
+
54
+ params.retry
55
+ end
56
+
57
+ def run_block(&block)
58
+ return block.call(create_state) if config.no_limit?
59
+
60
+ loop do
61
+ count, ttl = redis.increment(redis_key, period)
62
+
63
+ break(block.call(create_state(count: count, ttl: ttl))) if count <= limit
64
+
65
+ wait_for_interval(count)
66
+ end
67
+ end
68
+
69
+ def wait_for_interval(count)
70
+ ttl = redis.ttl(redis_key)
71
+ return if ttl.negative?
72
+
73
+ config.on_throttled.call(create_state(count: count, ttl: ttl)) if config.on_throttled.respond_to?(:call)
74
+ on_throttled.call(create_state(count: count, ttl: ttl)) if on_throttled.respond_to?(:call)
75
+
76
+ ttl = redis.ttl(redis_key)
77
+ return if ttl.negative?
78
+
79
+ sleep ttl
80
+ end
81
+
82
+ def redis
83
+ @redis ||= SpeedLimiter::Redis.new(config.redis || ::Redis.new(url: config.redis_url))
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "speed_limiter/state"
4
+
5
+ module SpeedLimiter
6
+ # Throttle params model
7
+ class ThrottleParams
8
+ def initialize(config:, key:, limit:, period:, **options)
9
+ @config = config
10
+ @key = key
11
+ @limit = limit
12
+ @period = period
13
+ @options = options
14
+ end
15
+
16
+ attr_reader :config, :key, :limit, :period
17
+
18
+ def on_throttled
19
+ @options[:on_throttled]
20
+ end
21
+
22
+ def retry
23
+ @options[:retry]
24
+ end
25
+
26
+ def redis_key
27
+ "#{config.prefix}:#{key}"
28
+ end
29
+
30
+ def create_state(count: nil, ttl: nil)
31
+ State.new(params: self, count: count, ttl: ttl)
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SpeedLimiter
4
- VERSION = "0.0.1"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/speed_limiter.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "speed_limiter/version"
4
4
  require "speed_limiter/config"
5
+ require "speed_limiter/throttle"
5
6
  require "redis"
6
7
 
7
8
  # Call speed limiter
@@ -15,56 +16,19 @@ module SpeedLimiter
15
16
  yield(config)
16
17
  end
17
18
 
18
- def redis
19
- @redis ||= config.redis || Redis.new(url: config.redis_url)
20
- end
21
-
22
- def throttle(key, limit:, period:, &block)
23
- return block&.call if config.no_limit?
24
-
25
- key_name = "#{config.prefix}:#{key}"
26
- loop do
27
- count = increment(key_name, period)
28
-
29
- break(block&.call) if count <= limit
30
-
31
- wait_for_interval(key_name)
32
- end
33
- end
34
-
35
- private
19
+ # @param key (see Throttle#initialize)
20
+ # @option (see Throttle#initialize)
21
+ # @yield (see Throttle#call)
22
+ # @yieldparam (see Throttle#call)
23
+ # @return Return value of block if argument contains block, otherwise Throttle instance
24
+ def throttle(key, **params, &block)
25
+ throttle = Throttle.new(key, config: config, **params)
36
26
 
37
- def wait_for_interval(key)
38
- pttl = redis.pttl(key)
39
- ttl = pttl / 1000.0
40
-
41
- return if ttl.negative?
42
-
43
- sleep ttl
44
- end
45
-
46
- def increment(key, period) # rubocop:disable Metrics/MethodLength
47
- if supports_expire_nx?
48
- count, = redis.pipelined do |pipeline|
49
- pipeline.incrby(key, 1)
50
- pipeline.call(:expire, key, period.to_i, "NX")
51
- end
27
+ if block
28
+ throttle.call(&block)
52
29
  else
53
- count, ttl = redis.pipelined do |pipeline|
54
- pipeline.incrby(key, 1)
55
- pipeline.ttl(key)
56
- end
57
- redis.expire(key, period.to_i) if ttl.negative?
30
+ throttle
58
31
  end
59
-
60
- count
61
- end
62
-
63
- def supports_expire_nx?
64
- return @supports_expire_nx if defined?(@supports_expire_nx)
65
-
66
- redis_versions = redis.info("server")["redis_version"]
67
- @supports_expire_nx = Gem::Version.new(redis_versions) >= Gem::Version.new("7.0.0")
68
32
  end
69
33
  end
70
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: speed_limiter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yuhei mukoyama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-30 00:00:00.000000000 Z
11
+ date: 2024-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -45,8 +45,12 @@ files:
45
45
  - compose.yaml
46
46
  - lib/speed_limiter.rb
47
47
  - lib/speed_limiter/config.rb
48
+ - lib/speed_limiter/redis.rb
49
+ - lib/speed_limiter/state.rb
50
+ - lib/speed_limiter/throttle.rb
51
+ - lib/speed_limiter/throttle_params.rb
48
52
  - lib/speed_limiter/version.rb
49
- - speed_limitter.gemspec
53
+ - speed_limiter.gemspec
50
54
  - throttle_server/config.ru
51
55
  - throttle_server/puma.rb
52
56
  - throttle_server/tmp/.keep
@@ -71,7 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
75
  - !ruby/object:Gem::Version
72
76
  version: '0'
73
77
  requirements: []
74
- rubygems_version: 3.2.22
78
+ rubygems_version: 3.5.7
75
79
  signing_key:
76
80
  specification_version: 4
77
81
  summary: Limit the frequency of execution across multiple threads and processes
File without changes