redis-throttle 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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