excess_flow 1.0.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 +7 -0
- data/.circleci/config.yml +35 -0
- data/.gitignore +11 -0
- data/.rspec +4 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +4 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +54 -0
- data/LICENSE.txt +201 -0
- data/README.md +174 -0
- data/Rakefile +8 -0
- data/bin/console +12 -0
- data/bin/setup +8 -0
- data/excess_flow.gemspec +28 -0
- data/lib/excess_flow/configuration.rb +67 -0
- data/lib/excess_flow/configuration_error.rb +22 -0
- data/lib/excess_flow/constants.rb +27 -0
- data/lib/excess_flow/failed_execution.rb +19 -0
- data/lib/excess_flow/fixed_window_strategy.rb +55 -0
- data/lib/excess_flow/global_mutex.rb +54 -0
- data/lib/excess_flow/rate_limited_execution_result.rb +32 -0
- data/lib/excess_flow/redis_connection.rb +61 -0
- data/lib/excess_flow/sliding_window_strategy.rb +77 -0
- data/lib/excess_flow/strategy.rb +46 -0
- data/lib/excess_flow/throttle_configuration.rb +76 -0
- data/lib/excess_flow/throttled_executor.rb +47 -0
- data/lib/excess_flow.rb +120 -0
- metadata +115 -0
data/lib/excess_flow.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019 ConvertKit, LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'connection_pool'
|
18
|
+
require 'redis'
|
19
|
+
|
20
|
+
require 'excess_flow/constants'
|
21
|
+
require 'excess_flow/configuration'
|
22
|
+
require 'excess_flow/redis_connection'
|
23
|
+
|
24
|
+
require 'excess_flow/global_mutex'
|
25
|
+
require 'excess_flow/failed_execution'
|
26
|
+
|
27
|
+
require 'excess_flow/throttle_configuration'
|
28
|
+
require 'excess_flow/throttled_executor'
|
29
|
+
require 'excess_flow/configuration_error'
|
30
|
+
|
31
|
+
require 'excess_flow/strategy'
|
32
|
+
require 'excess_flow/fixed_window_strategy'
|
33
|
+
require 'excess_flow/sliding_window_strategy'
|
34
|
+
require 'excess_flow/rate_limited_execution_result'
|
35
|
+
|
36
|
+
# = ExcessFlow
|
37
|
+
#
|
38
|
+
# Precise rate limiter with Redis as a backend. For more information on
|
39
|
+
# general usage consider consulting README.md file.
|
40
|
+
#
|
41
|
+
# While interacting with the rate limiter from within your application
|
42
|
+
# avoid re-using anything after :: notation as it is part of internal API
|
43
|
+
# and is subject to an un-announced breaking change.
|
44
|
+
#
|
45
|
+
# ExcessFlow provides 5 methods as part of it's public API:
|
46
|
+
# * configuration
|
47
|
+
# * configure
|
48
|
+
# * redis
|
49
|
+
# * redis_connection_pool
|
50
|
+
# * throttle
|
51
|
+
module ExcessFlow
|
52
|
+
module_function
|
53
|
+
|
54
|
+
# Provides access to cache's configuration.
|
55
|
+
#
|
56
|
+
# @return [Configuration] the object holding configuration values
|
57
|
+
def configuration
|
58
|
+
@configuration ||= Configuration.new
|
59
|
+
end
|
60
|
+
|
61
|
+
# API to configure cache dynamically during runtime.
|
62
|
+
#
|
63
|
+
# @yield [configuration] Takes in a block of code of code that is setting
|
64
|
+
# or changing configuration values
|
65
|
+
#
|
66
|
+
# @example Configure during runtime changing redis URL
|
67
|
+
# ExcessFlow.configure { |c| c.redis_url = 'foobar' }
|
68
|
+
#
|
69
|
+
# @return [void]
|
70
|
+
def configure
|
71
|
+
yield(configuration)
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
75
|
+
# API to communicate with Redis database backing cache up.
|
76
|
+
#
|
77
|
+
# @yield [redis]
|
78
|
+
#
|
79
|
+
# @example Store a value in Redis at given key
|
80
|
+
# Store.redis { |r| r.set('meaning_of_life', 42) }
|
81
|
+
#
|
82
|
+
# @return Returns a result of interaction with Redis
|
83
|
+
def redis
|
84
|
+
redis_connection_pool.with do |connection|
|
85
|
+
yield connection
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Accessor to connection pool. Defined on top level so it can be memoized
|
90
|
+
# on the topmost level
|
91
|
+
#
|
92
|
+
# @return [ConnectionPool] ConnectionPool object from connection_pool gem
|
93
|
+
def redis_connection_pool
|
94
|
+
@redis_connection_pool ||= ExcessFlow::RedisConnection.connection_pool
|
95
|
+
end
|
96
|
+
|
97
|
+
# Executes passed in block of code rate limited using specified strategy
|
98
|
+
# and arguments. Different call types can be differentiated and configured
|
99
|
+
# using arguments.
|
100
|
+
#
|
101
|
+
# @param key [String] key to identify your request to limit. Requests that are
|
102
|
+
# identified by same key share limits
|
103
|
+
# @param limit [Integer] number of requests that can be made in the specified
|
104
|
+
# time window
|
105
|
+
# @param ttl [Integer] size of window in seconds; how long it will take until
|
106
|
+
# the limits are reset
|
107
|
+
# @param strategy [Symbol] (optional) specifies which strategy to use to rate
|
108
|
+
# limit requests. Optional. Defaults to :fixed_window. Supported strategies
|
109
|
+
# are :fixed_window and :sliding_window.
|
110
|
+
#
|
111
|
+
# @return [ExcessFlow::RateLimitedExecutionResult] Execution result object that
|
112
|
+
# will hold result of your execution if it was under the limit. Accessible by
|
113
|
+
# calling `result` method. This object has two methods as part of it's public
|
114
|
+
# API: `result` (returns either result of execution or ExcessFlow::FailedExecution
|
115
|
+
# if limits were breached) and `success?` (returns `true` if request was within
|
116
|
+
# limits and else returns `false`).
|
117
|
+
def throttle(args, &block)
|
118
|
+
ExcessFlow::ThrottledExecutor.select_strategy_and_execute(args, &block)
|
119
|
+
end
|
120
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: excess_flow
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ConvertKit, LLC
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-10-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: connection_pool
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: redis
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Hihg precision simple redis based rate limiter.
|
56
|
+
email:
|
57
|
+
- engineering@convertkit.com
|
58
|
+
executables:
|
59
|
+
- console
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".circleci/config.yml"
|
64
|
+
- ".gitignore"
|
65
|
+
- ".rspec"
|
66
|
+
- ".rubocop.yml"
|
67
|
+
- ".travis.yml"
|
68
|
+
- CHANGELOG.md
|
69
|
+
- CODE_OF_CONDUCT.md
|
70
|
+
- Gemfile
|
71
|
+
- Gemfile.lock
|
72
|
+
- LICENSE.txt
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- bin/console
|
76
|
+
- bin/setup
|
77
|
+
- excess_flow.gemspec
|
78
|
+
- lib/excess_flow.rb
|
79
|
+
- lib/excess_flow/configuration.rb
|
80
|
+
- lib/excess_flow/configuration_error.rb
|
81
|
+
- lib/excess_flow/constants.rb
|
82
|
+
- lib/excess_flow/failed_execution.rb
|
83
|
+
- lib/excess_flow/fixed_window_strategy.rb
|
84
|
+
- lib/excess_flow/global_mutex.rb
|
85
|
+
- lib/excess_flow/rate_limited_execution_result.rb
|
86
|
+
- lib/excess_flow/redis_connection.rb
|
87
|
+
- lib/excess_flow/sliding_window_strategy.rb
|
88
|
+
- lib/excess_flow/strategy.rb
|
89
|
+
- lib/excess_flow/throttle_configuration.rb
|
90
|
+
- lib/excess_flow/throttled_executor.rb
|
91
|
+
homepage:
|
92
|
+
licenses:
|
93
|
+
- Apache License Version 2.0
|
94
|
+
metadata:
|
95
|
+
source_code_uri: https://github.com/ConvertKit/excess_flow
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubygems_version: 3.0.3
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: Redis based rate limiter
|
115
|
+
test_files: []
|