rapidity 0.0.3.59007 → 0.0.4.88264

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: 40693850bff25145da969b8f51894fbb7b01dc774ab6534e38cad3c4c461cbc7
4
- data.tar.gz: be8657014c79b06a6e7191d3e2aff293720ac5e9418591d3a4e962de4e4774eb
3
+ metadata.gz: b1ce2b9094e761e73932f6a5c4e249a54ab971fc89ee735b04c7748c68d562af
4
+ data.tar.gz: b33de26c3a4c10d18b087ba4ac168a9136764429b2a988be2814a591c7b82c5a
5
5
  SHA512:
6
- metadata.gz: f18ecca6be2877265cfa7d2afa434d515668502ea820a7fa0a41c805ab59e6163acda6c52b46dddc2c8396265e05ea8947c6b2f48e4c8c4dec3544ee23ac33e0
7
- data.tar.gz: 28869c4c007d2dba9012c006c5b09ab7157d0ce592a4ad891f365c5036096c28a9b9ddb1d85d17ecf31c744be07f09cdf924a6a4d73e594f200e416e8ce24e8c
6
+ metadata.gz: 4cc96ac7a6f910293ff9d1ca0218894a04605253fb41caa627dea3593850b4e4b1bb6d9bd892733353cdcde73a23f151c08aa0b55e473a8e5533497c23876ca9
7
+ data.tar.gz: 79db7352433e17fce63344856da58107b0fd87215b1d5f5e1207ff250cb2a73e8d8f5afb8287b13f7538269ec3df061dc783f632eeb98fa6b964ae485822a6eb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rapidity (0.0.3.59007)
4
+ rapidity (0.0.4.88264)
5
5
  activesupport
6
6
  connection_pool
7
7
  redis
@@ -58,7 +58,7 @@ GEM
58
58
  psych (3.3.2)
59
59
  public_suffix (4.0.6)
60
60
  rainbow (3.0.0)
61
- redis (4.4.0)
61
+ redis (4.7.0)
62
62
  reek (6.0.4)
63
63
  kwalify (~> 0.7.0)
64
64
  parser (~> 3.0.0)
@@ -142,4 +142,4 @@ DEPENDENCIES
142
142
  timeouter
143
143
 
144
144
  BUNDLED WITH
145
- 2.2.14
145
+ 2.2.27
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # Rapidity
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/rapidity.svg)](https://rubygems.org/gems/rapidity)
4
+ [![Gem](https://img.shields.io/gem/dt/rapidity.svg)](https://rubygems.org/gems/rapidity/versions)
5
+ [![YARD](https://badgen.net/badge/YARD/doc/blue)](http://www.rubydoc.info/gems/rapidity)
6
+
7
+ [![Coverage](https://lysander.rnds.pro/api/v1/badges/rapidity_coverage.svg)](https://lysander.rnds.pro/api/v1/badges/rapidity_coverage.html)
8
+ [![Quality](https://lysander.rnds.pro/api/v1/badges/rapidity_quality.svg)](https://lysander.rnds.pro/api/v1/badges/rapidity_quality.html)
9
+ [![Outdated](https://lysander.rnds.pro/api/v1/badges/rapidity_outdated.svg)](https://lysander.rnds.pro/api/v1/badges/rapidity_outdated.html)
10
+ [![Vulnerabilities](https://lysander.rnds.pro/api/v1/badges/rapidity_vulnerable.svg)](https://lysander.rnds.pro/api/v1/badges/rapidity_vulnerable.html)
11
+
12
+ Simple but fast Redis-backed distributed rate limiter. Allows you to specify time interval and count within to limit distributed operations.
13
+
14
+ Features:
15
+
16
+ - extremly simple
17
+ - safe
18
+ - fast
19
+
20
+ ## Usage
21
+
22
+ Rapidity has two variants:
23
+
24
+ - simple `Rapidity::Limiter` to handle single distibuted counter
25
+ - complex `Rapidity::Composer` to handle multiple counters at once
26
+
27
+ ### Single conter with concurrent access
28
+
29
+ ```ruby
30
+ pool = ConnectionPool.new(size: 10) do
31
+ Redis.new(url: ENV.fetch('REDIS_URL', 'redis://127.0.0.1:6379'))
32
+ end
33
+
34
+ # allow no more 10 requests within 5 seconds
35
+ limiter = Rapidity::Limiter.new(pool, name: 'requests', threshold: 10, interval: 5)
36
+
37
+ loop do
38
+ # try to obtain 3 requests at once
39
+ quota = limiter.obtain(3).times do
40
+ make_request
41
+ end
42
+
43
+ if quota == 0
44
+ # no more requests allowed within interval
45
+ sleep 1
46
+ end
47
+ end
48
+
49
+ ```
50
+
51
+ ### Multiple counters
52
+
53
+ ```ruby
54
+ pool = ConnectionPool.new(size: 10) do
55
+ Redis.new(url: ENV.fetch('REDIS_URL', 'redis://127.0.0.1:6379'))
56
+ end
57
+
58
+ LIMITS = [
59
+ { interval: 1, threshold: 2 }, # no more 2 requests per second
60
+ { interval: 60, threshold: 200 }, # no more 200 requests per minute
61
+ { interval: 86400, threshold: 10000 } # no more 10k requests per day
62
+ ]
63
+
64
+ limiter = Rapidity::Composer.new(pool, name: 'requests', limits: LIMITS)
65
+
66
+ loop do
67
+ # try to obtain 3 requests at once
68
+ quota = limiter.obtain(3).times do
69
+ make_request
70
+ end
71
+
72
+ if quota == 0
73
+ # no more requests allowed within interval
74
+ puts limiter.remains # inspect current limits
75
+ sleep 1
76
+ end
77
+ end
78
+
79
+ ```
80
+
81
+ ## Installation
82
+
83
+ It's a gem:
84
+ ```bash
85
+ gem install rapidity
86
+ ```
87
+ There's also the wonders of [the Gemfile](http://bundler.io):
88
+ ```ruby
89
+ gem 'rapidity'
90
+ ```
91
+
92
+
@@ -29,13 +29,13 @@ module Rapidity
29
29
  # Get current counter
30
30
  # @return remaining counter value
31
31
  def remains
32
- _, result = @pool.with do |conn|
32
+ results = @pool.with do |conn|
33
33
  conn.multi do
34
34
  conn.set(key('remains'), threshold, ex: interval, nx: true)
35
35
  conn.get(key('remains'))
36
36
  end
37
37
  end
38
- result.to_i
38
+ results[1].to_i #=> conn.get(key('remains'))
39
39
  end
40
40
 
41
41
  # Obtain values from counter
@@ -43,24 +43,35 @@ module Rapidity
43
43
  def obtain(count = 5)
44
44
  count = count.abs
45
45
 
46
- _, taken = @pool.with do |conn|
46
+ results = @pool.with do |conn|
47
47
  conn.multi do
48
48
  conn.set(key('remains'), threshold, ex: interval, nx: true)
49
49
  conn.decrby(key('remains'), count)
50
50
  end
51
51
  end
52
52
 
53
+ taken = results[1].to_i #=> conn.decrby(key('remains'), count)
54
+
53
55
  if taken < 0
54
56
  overflow = taken.abs
55
57
  to_return = [count, overflow].min
56
58
 
57
- @pool.with do |conn|
59
+ results = @pool.with do |conn|
58
60
  conn.multi do
59
61
  conn.set(key('remains'), threshold - to_return, ex: interval, nx: true)
60
62
  conn.incrby(key('remains'), to_return)
63
+ conn.ttl(key('remains'))
61
64
  end
62
65
  end
63
66
 
67
+ ttl = results[2].to_i #=> conn.ttl(key('remains'))
68
+
69
+ # reset if no ttl present
70
+ if ttl == -1
71
+ STDERR.puts "ERROR[#{Time.now}]: TTL for key #{key('remains').inspect} disappeared!"
72
+ @pool.with {|c| c.expire(key('remains'), interval) }
73
+ end
74
+
64
75
  count - to_return
65
76
  else
66
77
  count
@@ -1,6 +1,6 @@
1
1
  module Rapidity
2
2
 
3
- VERSION = '0.0.3'.freeze
3
+ VERSION = '0.0.4'.freeze
4
4
 
5
5
  end
6
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rapidity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3.59007
4
+ version: 0.0.4.88264
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yurusov Vlad
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-08-04 00:00:00.000000000 Z
12
+ date: 2022-06-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -232,6 +232,7 @@ files:
232
232
  - Gemfile
233
233
  - Gemfile.lock
234
234
  - LICENSE
235
+ - README.md
235
236
  - lib/rapidity.rb
236
237
  - lib/rapidity/composer.rb
237
238
  - lib/rapidity/limiter.rb