redis-throttle 1.0.0 → 1.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.
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./api"
4
-
5
- class Redis
6
- class Throttle
7
- module ClassMethods
8
- # Syntax sugar for {Throttle#concurrency}.
9
- #
10
- # @see #concurrency
11
- # @param (see Throttle#initialize)
12
- # @param (see Throttle#concurrency)
13
- # @return (see Throttle#concurrency)
14
- def concurrency(bucket, limit:, ttl:, redis: nil)
15
- new(:redis => redis).concurrency(bucket, :limit => limit, :ttl => ttl)
16
- end
17
-
18
- # Syntax sugar for {Throttle#rate_limit}.
19
- #
20
- # @see #concurrency
21
- # @param (see Throttle#initialize)
22
- # @param (see Throttle#rate_limit)
23
- # @return (see Throttle#rate_limit)
24
- def rate_limit(bucket, limit:, period:, redis: nil)
25
- new(:redis => redis).rate_limit(bucket, :limit => limit, :period => period)
26
- end
27
-
28
- # Return usage info for all known (in use) strategies.
29
- #
30
- # @example
31
- # Redis::Throttle.info(:match => "*_api").each do |strategy, current_value|
32
- # # ...
33
- # end
34
- #
35
- # @param match [#to_s]
36
- # @return (see Api#info)
37
- def info(match: "*", redis: nil)
38
- api = Api.new(:redis => redis)
39
- strategies = api.strategies(:match => match.to_s)
40
-
41
- api.info(:strategies => strategies)
42
- end
43
- end
44
- end
45
- end
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Redis
4
- class Throttle
5
- class Concurrency
6
- # @!attribute [r] bucket
7
- # @return [String] Throttling group name
8
- attr_reader :bucket
9
-
10
- # @!attribute [r] limit
11
- # @return [Integer] Max allowed concurrent units
12
- attr_reader :limit
13
-
14
- # @!attribute [r] ttl
15
- # @return [Integer] Time (in seconds) to hold the lock before
16
- # releasing it (in case it wasn't released already)
17
- attr_reader :ttl
18
-
19
- # @param bucket [#to_s] Throttling group name
20
- # @param limit [#to_i] Max allowed concurrent units
21
- # @param ttl [#to_i] Time (in seconds) to hold the lock before
22
- # releasing it (in case it wasn't released already)
23
- def initialize(bucket, limit:, ttl:)
24
- @bucket = -bucket.to_s
25
- @limit = limit.to_i
26
- @ttl = ttl.to_i
27
- end
28
-
29
- # Returns `true` if `other` is a {Concurrency} instance with the same
30
- # {#bucket}, {#limit}, and {#ttl}.
31
- #
32
- # @see https://docs.ruby-lang.org/en/master/Object.html#method-i-eql-3F
33
- # @param other [Object]
34
- # @return [Boolean]
35
- def ==(other)
36
- return true if equal? other
37
- return false unless other.is_a?(self.class)
38
-
39
- @bucket == other.bucket && @limit == other.limit && @ttl == other.ttl
40
- end
41
-
42
- alias eql? ==
43
-
44
- # @api private
45
- #
46
- # Compare `self` with `other` strategy:
47
- #
48
- # - Returns `nil` if `other` is neither {Concurrency} nor {RateLimit}
49
- # - Returns `1` if `other` is a {RateLimit}
50
- # - Returns `1` if `other` is a {Concurrency} with lower {#limit}
51
- # - Returns `0` if `other` is a {Concurrency} with the same {#limit}
52
- # - Returns `-1` if `other` is a {Concurrency} with bigger {#limit}
53
- #
54
- # @return [-1, 0, 1, nil]
55
- def <=>(other)
56
- complexity <=> other.complexity if other.respond_to? :complexity
57
- end
58
-
59
- # @api private
60
- #
61
- # Generates an Integer hash value for this object.
62
- #
63
- # @see https://docs.ruby-lang.org/en/master/Object.html#method-i-hash
64
- # @return [Integer]
65
- def hash
66
- @hash ||= [@bucket, @limit, @ttl].hash
67
- end
68
-
69
- # @api private
70
- #
71
- # @return [Array(Integer, Integer)] Strategy complexity pseudo-score
72
- def complexity
73
- [1, @limit]
74
- end
75
- end
76
- end
77
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Redis
4
- class Throttle
5
- class Error < StandardError; end
6
- class ScriptError < Error; end
7
-
8
- class FrozenError < RuntimeError; end if RUBY_VERSION < "2.5"
9
- end
10
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Redis
4
- class Throttle
5
- class RateLimit
6
- # @!attribute [r] bucket
7
- # @return [String] Throttling group name
8
- attr_reader :bucket
9
-
10
- # @!attribute [r] limit
11
- # @return [Integer] Max allowed units per {#period}
12
- attr_reader :limit
13
-
14
- # @!attribute [r] period
15
- # @return [Integer] Period in seconds
16
- attr_reader :period
17
-
18
- # @param bucket [#to_s] Throttling group name
19
- # @param limit [#to_i] Max allowed units per `period`
20
- # @param period [#to_i] Period in seconds
21
- def initialize(bucket, limit:, period:)
22
- @bucket = -bucket.to_s
23
- @limit = limit.to_i
24
- @period = period.to_i
25
- end
26
-
27
- # Returns `true` if `other` is a {RateLimit} instance with the same
28
- # {#bucket}, {#limit}, and {#period}.
29
- #
30
- # @see https://docs.ruby-lang.org/en/master/Object.html#method-i-eql-3F
31
- # @param other [Object]
32
- # @return [Boolean]
33
- def ==(other)
34
- return true if equal? other
35
- return false unless other.is_a?(self.class)
36
-
37
- @bucket == other.bucket && @limit == other.limit && @period == other.period
38
- end
39
-
40
- alias eql? ==
41
-
42
- # @api private
43
- #
44
- # Compare `self` with `other` strategy:
45
- #
46
- # - Returns `nil` if `other` is neither {Concurrency} nor {RateLimit}
47
- # - Returns `-1` if `other` is a {Concurrency}
48
- # - Returns `1` if `other` is a {RateLimit} with lower {#limit}
49
- # - Returns `0` if `other` is a {RateLimit} with the same {#limit}
50
- # - Returns `-1` if `other` is a {RateLimit} with bigger {#limit}
51
- #
52
- # @return [-1, 0, 1, nil]
53
- def <=>(other)
54
- complexity <=> other.complexity if other.respond_to? :complexity
55
- end
56
-
57
- # @api private
58
- #
59
- # Generates an Integer hash value for this object.
60
- #
61
- # @see https://docs.ruby-lang.org/en/master/Object.html#method-i-hash
62
- # @return [Integer]
63
- def hash
64
- @hash ||= [@bucket, @limit, @period].hash
65
- end
66
-
67
- # @api private
68
- #
69
- # @return [Array(Integer, Integer)] Strategy complexity pseudo-score
70
- def complexity
71
- [0, @limit]
72
- end
73
- end
74
- end
75
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "digest"
4
- require "redis/errors"
5
-
6
- require_relative "./errors"
7
-
8
- class Redis
9
- class Throttle
10
- # @api private
11
- #
12
- # Lazy-compile and run acquire script by it's sha1 digest.
13
- class Script
14
- # Redis error fired when script ID is unkown.
15
- NOSCRIPT = "NOSCRIPT"
16
- private_constant :NOSCRIPT
17
-
18
- LUA_ERROR_MESSAGE = %r{
19
- ERR\s
20
- (?<message>Error\s(?:compiling|running)\sscript)
21
- \s\([^()]+\):\s
22
- (?:@[^:]+:\d+:\s)?
23
- [^:]+:(?<loc>\d+):\s
24
- (?<details>.+)
25
- }x.freeze
26
- private_constant :LUA_ERROR_MESSAGE
27
-
28
- def initialize(source)
29
- @source = -source.to_s
30
- @digest = Digest::SHA1.hexdigest(@source).freeze
31
- end
32
-
33
- def call(redis, keys: [], argv: [])
34
- __eval__(redis, keys, argv)
35
- rescue Redis::CommandError => e
36
- md = LUA_ERROR_MESSAGE.match(e.message.to_s)
37
- raise unless md
38
-
39
- raise ScriptError, "#{md[:message]} @#{md[:loc]}: #{md[:details]}"
40
- end
41
-
42
- private
43
-
44
- def __eval__(redis, keys, argv)
45
- redis.evalsha(@digest, keys, argv)
46
- rescue Redis::CommandError => e
47
- raise unless e.message.include?(NOSCRIPT)
48
-
49
- redis.eval(@source, keys, argv)
50
- end
51
- end
52
- end
53
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Redis
4
- class Throttle
5
- # Gem version.
6
- VERSION = "1.0.0"
7
- end
8
- end
File without changes