rapidity 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 567c4170351523c2e8850ea4980d0a5099c4bab64bddc1bd60d789aa1eb9d2be
4
+ data.tar.gz: f148f201500e64d68fe23bf101c7ed21c42d8bc3486c1ee783b97e7117d24711
5
+ SHA512:
6
+ metadata.gz: 9ccac974c7d5bfd96b49a61c98f7db8a731667e97cb614c8a34d465173540f9b8f05e1dea8d6797ee4c4f8112b38471d28b8d92008a9722da9b1080a947b7d8c
7
+ data.tar.gz: a0ec68f61eb62c09be61637629d56d628b66af4b03ca0eb31351d9434b24bbb6233314b7e1864c3d28acf04b4827a5bdbb1d25d2f00b6593381e6cc00307f177
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in aggredator-brick.gemspec
6
+ gemspec
7
+
data/Gemfile.lock ADDED
@@ -0,0 +1,144 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rapidity (0.0.1)
5
+ activesupport
6
+ connection_pool
7
+ redis
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (6.1.3.2)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ zeitwerk (~> 2.3)
18
+ addressable (2.7.0)
19
+ public_suffix (>= 2.0.2, < 5.0)
20
+ ansi (1.5.0)
21
+ ast (2.4.2)
22
+ awesome_print (1.9.2)
23
+ axiom-types (0.1.1)
24
+ descendants_tracker (~> 0.0.4)
25
+ ice_nine (~> 0.11.0)
26
+ thread_safe (~> 0.3, >= 0.3.1)
27
+ bump (0.10.0)
28
+ byebug (11.1.3)
29
+ coercible (1.0.0)
30
+ descendants_tracker (~> 0.0.1)
31
+ concurrent-ruby (1.1.8)
32
+ connection_pool (2.2.5)
33
+ descendants_tracker (0.0.4)
34
+ thread_safe (~> 0.3, >= 0.3.1)
35
+ diff-lcs (1.4.4)
36
+ docile (1.4.0)
37
+ equalizer (0.0.11)
38
+ erubis (2.7.0)
39
+ flay (2.12.1)
40
+ erubis (~> 2.7.0)
41
+ path_expander (~> 1.0)
42
+ ruby_parser (~> 3.0)
43
+ sexp_processor (~> 4.0)
44
+ flog (4.6.4)
45
+ path_expander (~> 1.0)
46
+ ruby_parser (~> 3.1, > 3.1.0)
47
+ sexp_processor (~> 4.8)
48
+ i18n (1.8.10)
49
+ concurrent-ruby (~> 1.0)
50
+ ice_nine (0.11.2)
51
+ kwalify (0.7.2)
52
+ launchy (2.5.0)
53
+ addressable (~> 2.7)
54
+ minitest (5.14.4)
55
+ parser (3.0.1.1)
56
+ ast (~> 2.4.1)
57
+ path_expander (1.1.0)
58
+ psych (3.3.2)
59
+ public_suffix (4.0.6)
60
+ rainbow (3.0.0)
61
+ redis (4.3.1)
62
+ reek (6.0.4)
63
+ kwalify (~> 0.7.0)
64
+ parser (~> 3.0.0)
65
+ psych (~> 3.1)
66
+ rainbow (>= 2.0, < 4.0)
67
+ rspec (3.10.0)
68
+ rspec-core (~> 3.10.0)
69
+ rspec-expectations (~> 3.10.0)
70
+ rspec-mocks (~> 3.10.0)
71
+ rspec-collection_matchers (1.2.0)
72
+ rspec-expectations (>= 2.99.0.beta1)
73
+ rspec-core (3.10.1)
74
+ rspec-support (~> 3.10.0)
75
+ rspec-expectations (3.10.1)
76
+ diff-lcs (>= 1.2.0, < 2.0)
77
+ rspec-support (~> 3.10.0)
78
+ rspec-mocks (3.10.2)
79
+ diff-lcs (>= 1.2.0, < 2.0)
80
+ rspec-support (~> 3.10.0)
81
+ rspec-support (3.10.2)
82
+ rspec_junit_formatter (0.4.1)
83
+ rspec-core (>= 2, < 4, != 2.12.0)
84
+ ruby_parser (3.16.0)
85
+ sexp_processor (~> 4.15, >= 4.15.1)
86
+ rubycritic (4.6.1)
87
+ flay (~> 2.8)
88
+ flog (~> 4.4)
89
+ launchy (>= 2.0.0)
90
+ parser (>= 2.6.0)
91
+ rainbow (~> 3.0)
92
+ reek (~> 6.0, < 7.0)
93
+ ruby_parser (~> 3.8)
94
+ simplecov (>= 0.17.0)
95
+ tty-which (~> 0.4.0)
96
+ virtus (~> 1.0)
97
+ sexp_processor (4.15.3)
98
+ shoulda-matchers (4.5.1)
99
+ activesupport (>= 4.2.0)
100
+ simplecov (0.21.2)
101
+ docile (~> 1.1)
102
+ simplecov-html (~> 0.11)
103
+ simplecov_json_formatter (~> 0.1)
104
+ simplecov-console (0.9.1)
105
+ ansi
106
+ simplecov
107
+ terminal-table
108
+ simplecov-html (0.12.3)
109
+ simplecov_json_formatter (0.1.3)
110
+ terminal-table (3.0.1)
111
+ unicode-display_width (>= 1.1.1, < 3)
112
+ thread_safe (0.3.6)
113
+ timeouter (0.1.3.38794)
114
+ tty-which (0.4.2)
115
+ tzinfo (2.0.4)
116
+ concurrent-ruby (~> 1.0)
117
+ unicode-display_width (2.0.0)
118
+ virtus (1.0.5)
119
+ axiom-types (~> 0.1)
120
+ coercible (~> 1.0)
121
+ descendants_tracker (~> 0.0, >= 0.0.3)
122
+ equalizer (~> 0.0, >= 0.0.9)
123
+ zeitwerk (2.4.2)
124
+
125
+ PLATFORMS
126
+ x86_64-linux
127
+
128
+ DEPENDENCIES
129
+ awesome_print
130
+ bump
131
+ bundler (~> 2.0)
132
+ byebug
133
+ rapidity!
134
+ rspec (~> 3.0)
135
+ rspec-collection_matchers
136
+ rspec_junit_formatter
137
+ rubycritic
138
+ shoulda-matchers
139
+ simplecov
140
+ simplecov-console
141
+ timeouter
142
+
143
+ BUNDLED WITH
144
+ 2.2.13
data/lib/rapidity.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'redis'
2
+ require_relative 'rapidity/version'
3
+ require_relative 'rapidity/limiter'
4
+ require_relative 'rapidity/composer'
5
+
6
+ module Rapidity
7
+
8
+
9
+
10
+ end
11
+
@@ -0,0 +1,55 @@
1
+
2
+ require 'ostruct'
3
+
4
+ require_relative './limiter'
5
+
6
+
7
+ module Rapidity
8
+ class Composer
9
+
10
+ attr_reader :limits, :limiters, :name, :namespace
11
+
12
+ # Combine multiple limits
13
+ # @params pool - inititalized Redis pool
14
+ # @params name - limiter name - part of the Redis key name
15
+ # @params limits - multiple limits definition
16
+
17
+ ## limits example
18
+ # ```ruby`
19
+ #limits = [
20
+ # { threshold: 2, interval: 1 }, # 2 events per second
21
+ # { threshold: 9, interval: 5 }, # 9 events per 5 seconds
22
+ # { threshold: 20, interval: 20 }, # 20 events per 20 seconds
23
+ # { threshold: 42, interval: 60 }, # 42 events per 60 seconds
24
+ #]
25
+ #```
26
+
27
+ # @params namespace - namespace for Redis keys
28
+ def initialize pool, name:, limits: [], namespace: 'rapidity'
29
+ @limits = limits
30
+ @name = name
31
+ @namespace = namespace
32
+
33
+ @limiters = @limits.map.each_with_index do |l, i|
34
+ limit = OpenStruct.new(l)
35
+ ::Rapidity::Limiter.new(pool, name: "#{i}_#{name}_#{limit.limit}/#{limit.interval}", interval: limit.interval, threshold: limit.threshold, namespace: namespace)
36
+ end
37
+ end
38
+
39
+ def remains
40
+ @limiters.each_with_object({}) do |limiter, result|
41
+ result[limiter.name] = limiter.remains
42
+ end
43
+ end
44
+
45
+ def obtain(count = 5)
46
+ @limiters.each do |limiter|
47
+ count = limiter.obtain(count)
48
+ break if count == 0
49
+ end
50
+
51
+ return count
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,72 @@
1
+
2
+ require 'connection_pool'
3
+ require 'redis'
4
+
5
+ module Rapidity
6
+ class Limiter
7
+
8
+ attr_reader :pool, :name, :interval, :threshold, :namespace
9
+
10
+
11
+ # Convert message to given class
12
+ # @params pool - inititalized Redis pool
13
+ # @params name - limiter name - part of the Redis key name
14
+ # @params interval - interval in seconds to apply this limit
15
+ # @params threshold - maximum available events for this interval
16
+ # @params namespace - namespace for Redis keys
17
+ def initialize pool, name:, interval: 10, threshold: 10, namespace: 'rapidity'
18
+ @pool = pool
19
+ @interval = interval
20
+ @threshold = threshold
21
+ @name = name
22
+
23
+ @namespace = namespace
24
+ end
25
+
26
+ def key(path)
27
+ "#{namespace}:#{name}_#{path}"
28
+ end
29
+
30
+ # Get current counter
31
+ # @return remaining counter value
32
+ def remains
33
+ _, result = @pool.with do |conn|
34
+ conn.multi do
35
+ conn.set(key('remains'), threshold, ex: interval, nx: true)
36
+ conn.get(key('remains'))
37
+ end
38
+ end
39
+ result.to_i
40
+ end
41
+
42
+ # Obtain values from counter
43
+ # @return count succesfuly obtained send slots
44
+ def obtain(count = 5)
45
+ _, taken = @pool.with do |conn|
46
+ conn.multi do
47
+ conn.set(key('remains'), threshold, ex: interval, nx: true)
48
+ conn.decrby(key('remains'), count)
49
+ end
50
+ end
51
+
52
+ obtained = if taken < 0
53
+ overflow = taken.abs
54
+ to_return = [count, overflow].min
55
+
56
+ @pool.with do |conn|
57
+ conn.multi do
58
+ conn.set(key('remains'), threshold - to_return, ex: interval, nx: true)
59
+ conn.incrby(key('remains'), to_return)
60
+ end
61
+ end
62
+
63
+ count - overflow
64
+ else
65
+ count
66
+ end
67
+
68
+ return obtained
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ module Rapidity
2
+ VERSION='0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,260 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rapidity
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Yurusov Vlad
8
+ - Samoilenko Yuri
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-08-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: redis
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: connection_pool
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: timeouter
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: bundler
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '2.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '2.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3.0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '3.0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: awesome_print
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: bump
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: byebug
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: rspec-collection_matchers
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: rspec_junit_formatter
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ - !ruby/object:Gem::Dependency
169
+ name: rubycritic
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ type: :development
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: shoulda-matchers
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ - !ruby/object:Gem::Dependency
197
+ name: simplecov
198
+ requirement: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ - !ruby/object:Gem::Dependency
211
+ name: simplecov-console
212
+ requirement: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ version: '0'
217
+ type: :development
218
+ prerelease: false
219
+ version_requirements: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
224
+ description: Simple distributed Redis-backed rate limiter
225
+ email:
226
+ - vyurusov@rnds.pro
227
+ - kinnalru@gmail.com
228
+ executables: []
229
+ extensions: []
230
+ extra_rdoc_files: []
231
+ files:
232
+ - Gemfile
233
+ - Gemfile.lock
234
+ - lib/rapidity.rb
235
+ - lib/rapidity/composer.rb
236
+ - lib/rapidity/limiter.rb
237
+ - lib/rapidity/version.rb
238
+ homepage:
239
+ licenses: []
240
+ metadata: {}
241
+ post_install_message:
242
+ rdoc_options: []
243
+ require_paths:
244
+ - lib
245
+ required_ruby_version: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - ">="
248
+ - !ruby/object:Gem::Version
249
+ version: '0'
250
+ required_rubygems_version: !ruby/object:Gem::Requirement
251
+ requirements:
252
+ - - ">="
253
+ - !ruby/object:Gem::Version
254
+ version: '0'
255
+ requirements: []
256
+ rubygems_version: 3.2.13
257
+ signing_key:
258
+ specification_version: 4
259
+ summary: Simple distributed Redis-backed rate limiter
260
+ test_files: []