freno-client 0.8.0 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +35 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +31 -166
- data/Gemfile +5 -1
- data/README.md +2 -4
- data/Rakefile +2 -0
- data/freno-client.gemspec +7 -3
- data/gemfiles/faraday_0.gemfile +22 -0
- data/gemfiles/faraday_1.gemfile +22 -0
- data/gemfiles/faraday_2.gemfile +22 -0
- data/lib/freno/client/errors.rb +2 -0
- data/lib/freno/client/preconditions.rb +4 -2
- data/lib/freno/client/request.rb +9 -8
- data/lib/freno/client/requests/check.rb +2 -1
- data/lib/freno/client/requests/check_read.rb +2 -1
- data/lib/freno/client/requests/replication_delay.rb +2 -1
- data/lib/freno/client/result.rb +3 -1
- data/lib/freno/client/version.rb +3 -1
- data/lib/freno/client.rb +59 -19
- data/lib/freno/throttler/circuit_breaker.rb +2 -2
- data/lib/freno/throttler/errors.rb +2 -1
- data/lib/freno/throttler/instrumenter.rb +3 -3
- data/lib/freno/throttler/mapper.rb +2 -2
- data/lib/freno/throttler.rb +31 -22
- metadata +14 -10
- data/.travis.yml +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 808823b23d76b3a540d9d17d2c6e28b428fd3cb387c941f79c749779393ac462
|
4
|
+
data.tar.gz: cf58a8db9c3d7fa2bea92727b3336a62fded79081723ee5e13555a72e6d68c62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fb13835bd9d2c9dd64c8bc3ae6e9931e0bd16a82cfa0ffbc4ed276505e453d4cf8a371cd66e6a0da19c2755e1174ce2812c55d0b12ce781b7a52f08add3f838
|
7
|
+
data.tar.gz: 540f2de04000141a1c636ab169e178a99a48dc19fe53557f7afba59dd2ddd2e2c407178e8a4f5e2daeb82b54871eac21f7d369854f1e9d7b87bbde1226289ffc
|
@@ -0,0 +1,35 @@
|
|
1
|
+
name: Ruby
|
2
|
+
on:
|
3
|
+
push:
|
4
|
+
branches:
|
5
|
+
- main
|
6
|
+
pull_request:
|
7
|
+
branches:
|
8
|
+
- main
|
9
|
+
permissions:
|
10
|
+
contents: read
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
ruby-version:
|
17
|
+
- '2.7'
|
18
|
+
- '3.0'
|
19
|
+
- '3.1'
|
20
|
+
gemfile-path:
|
21
|
+
- Gemfile
|
22
|
+
- gemfiles/faraday_0.gemfile
|
23
|
+
- gemfiles/faraday_1.gemfile
|
24
|
+
- gemfiles/faraday_2.gemfile
|
25
|
+
env:
|
26
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile-path }}
|
27
|
+
steps:
|
28
|
+
- uses: actions/checkout@v3
|
29
|
+
- name: Set up Ruby
|
30
|
+
uses: ruby/setup-ruby@v1
|
31
|
+
with:
|
32
|
+
ruby-version: ${{ matrix.ruby-version }}
|
33
|
+
bundler-cache: true
|
34
|
+
- name: Run tests
|
35
|
+
run: bundle exec rake
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,179 +1,44 @@
|
|
1
|
-
require:
|
1
|
+
require:
|
2
|
+
- rubocop-minitest
|
3
|
+
- rubocop-performance
|
4
|
+
- rubocop-rake
|
2
5
|
|
3
6
|
AllCops:
|
4
|
-
|
5
|
-
TargetRubyVersion: 2.
|
7
|
+
NewCops: enable
|
8
|
+
TargetRubyVersion: 2.7
|
6
9
|
|
7
|
-
|
8
|
-
Enabled: true
|
9
|
-
Bundler/OrderedGems:
|
10
|
-
Enabled: true
|
11
|
-
|
12
|
-
Layout/BlockAlignment:
|
13
|
-
Enabled: true
|
14
|
-
Layout/BlockEndNewline:
|
15
|
-
Enabled: true
|
16
|
-
Layout/ConditionPosition:
|
17
|
-
Enabled: true
|
18
|
-
Layout/DefEndAlignment:
|
19
|
-
Enabled: true
|
20
|
-
Layout/EndOfLine:
|
21
|
-
Enabled: true
|
22
|
-
Layout/IndentationStyle:
|
23
|
-
Enabled: true
|
24
|
-
Layout/InitialIndentation:
|
25
|
-
Enabled: true
|
26
|
-
Layout/SpaceAfterColon:
|
27
|
-
Enabled: true
|
28
|
-
Layout/SpaceAfterComma:
|
29
|
-
Enabled: true
|
30
|
-
Layout/SpaceAfterMethodName:
|
31
|
-
Enabled: true
|
32
|
-
Layout/SpaceAfterNot:
|
33
|
-
Enabled: true
|
34
|
-
Layout/SpaceAfterSemicolon:
|
35
|
-
Enabled: true
|
36
|
-
Layout/SpaceAroundBlockParameters:
|
37
|
-
Enabled: true
|
38
|
-
Layout/SpaceAroundEqualsInParameterDefault:
|
39
|
-
Enabled: true
|
40
|
-
Layout/SpaceInsideArrayPercentLiteral:
|
41
|
-
Enabled: true
|
42
|
-
Layout/SpaceInsideParens:
|
43
|
-
Enabled: true
|
44
|
-
Layout/SpaceInsideRangeLiteral:
|
45
|
-
Enabled: true
|
46
|
-
Layout/TrailingEmptyLines:
|
47
|
-
Enabled: true
|
48
|
-
Layout/TrailingWhitespace:
|
49
|
-
Enabled: true
|
50
|
-
|
51
|
-
Lint/CircularArgumentReference:
|
52
|
-
Enabled: true
|
53
|
-
Lint/Debugger:
|
54
|
-
Enabled: true
|
55
|
-
Lint/DeprecatedClassMethods:
|
56
|
-
Enabled: true
|
57
|
-
Lint/DuplicateHashKey:
|
58
|
-
Enabled: true
|
59
|
-
Lint/DuplicateMethods:
|
60
|
-
Enabled: true
|
61
|
-
Lint/EachWithObjectArgument:
|
62
|
-
Enabled: true
|
63
|
-
Lint/ElseLayout:
|
64
|
-
Enabled: true
|
65
|
-
Lint/EmptyEnsure:
|
66
|
-
Enabled: true
|
67
|
-
Lint/EmptyInterpolation:
|
68
|
-
Enabled: true
|
69
|
-
Lint/EnsureReturn:
|
70
|
-
Enabled: true
|
71
|
-
Lint/FlipFlop:
|
72
|
-
Enabled: true
|
73
|
-
Lint/FloatOutOfRange:
|
74
|
-
Enabled: true
|
75
|
-
Lint/FormatParameterMismatch:
|
76
|
-
Enabled: true
|
77
|
-
Lint/LiteralInInterpolation:
|
78
|
-
Enabled: true
|
79
|
-
Lint/Loop:
|
80
|
-
Enabled: true
|
81
|
-
Lint/NextWithoutAccumulator:
|
82
|
-
Enabled: true
|
83
|
-
Lint/RandOne:
|
84
|
-
Enabled: true
|
85
|
-
Lint/RedundantSplatExpansion:
|
86
|
-
Enabled: true
|
87
|
-
Lint/RedundantStringCoercion:
|
88
|
-
Enabled: true
|
89
|
-
Lint/RequireParentheses:
|
90
|
-
Enabled: true
|
91
|
-
Lint/RescueException:
|
92
|
-
Enabled: true
|
93
|
-
Lint/UnderscorePrefixedVariableName:
|
94
|
-
Enabled: true
|
95
|
-
Lint/UnreachableCode:
|
96
|
-
Enabled: true
|
97
|
-
Lint/UselessComparison:
|
98
|
-
Enabled: true
|
99
|
-
Lint/UselessSetterCall:
|
100
|
-
Enabled: true
|
101
|
-
Lint/Void:
|
10
|
+
Layout/MultilineMethodCallIndentation:
|
102
11
|
Enabled: true
|
12
|
+
EnforcedStyle: indented_relative_to_receiver
|
103
13
|
|
104
|
-
|
105
|
-
Enabled:
|
106
|
-
Naming/ClassAndModuleCamelCase:
|
107
|
-
Enabled: true
|
108
|
-
Naming/FileName:
|
109
|
-
Enabled: true
|
110
|
-
Naming/MethodName:
|
111
|
-
Enabled: true
|
14
|
+
Metrics:
|
15
|
+
Enabled: false
|
112
16
|
|
113
|
-
|
114
|
-
Enabled:
|
115
|
-
|
116
|
-
Enabled:
|
117
|
-
|
118
|
-
Enabled:
|
119
|
-
|
120
|
-
Enabled:
|
121
|
-
|
122
|
-
Enabled:
|
123
|
-
Performance/RedundantMerge:
|
124
|
-
Enabled: true
|
125
|
-
MaxKeyValuePairs: 1
|
126
|
-
Performance/ReverseEach:
|
127
|
-
Enabled: true
|
128
|
-
Performance/Size:
|
129
|
-
Enabled: true
|
130
|
-
Performance/StartWith:
|
131
|
-
Enabled: true
|
17
|
+
Minitest/AssertEmptyLiteral:
|
18
|
+
Enabled: false
|
19
|
+
Minitest/AssertEqual:
|
20
|
+
Enabled: false
|
21
|
+
Minitest/AssertPredicate:
|
22
|
+
Enabled: false
|
23
|
+
Minitest/MultipleAssertions:
|
24
|
+
Enabled: false
|
25
|
+
Minitest/RefutePredicate:
|
26
|
+
Enabled: false
|
132
27
|
|
133
|
-
|
28
|
+
Naming/RescuedExceptionsVariableName:
|
134
29
|
Enabled: true
|
30
|
+
PreferredName: error
|
135
31
|
|
136
|
-
Style/
|
137
|
-
Enabled: true
|
138
|
-
Style/BeginBlock:
|
139
|
-
Enabled: true
|
140
|
-
Style/BlockComments:
|
141
|
-
Enabled: true
|
142
|
-
Style/CaseEquality:
|
143
|
-
Enabled: true
|
144
|
-
Style/CharacterLiteral:
|
145
|
-
Enabled: true
|
146
|
-
Style/ClassMethods:
|
147
|
-
Enabled: true
|
148
|
-
Style/DefWithParentheses:
|
149
|
-
Enabled: true
|
150
|
-
Style/EndBlock:
|
151
|
-
Enabled: true
|
152
|
-
Style/For:
|
153
|
-
Enabled: true
|
154
|
-
Style/HashSyntax:
|
155
|
-
Enabled: true
|
156
|
-
EnforcedStyle: ruby19
|
157
|
-
Style/LambdaCall:
|
158
|
-
Enabled: true
|
159
|
-
Style/MethodCallWithoutArgsParentheses:
|
160
|
-
Enabled: true
|
161
|
-
Style/MethodDefParentheses:
|
162
|
-
Enabled: true
|
163
|
-
Style/MultilineIfThen:
|
164
|
-
Enabled: true
|
165
|
-
Style/NilComparison:
|
166
|
-
Enabled: true
|
167
|
-
Style/Not:
|
168
|
-
Enabled: true
|
169
|
-
Style/OneLineConditional:
|
170
|
-
Enabled: true
|
171
|
-
Style/RedundantSortBy:
|
172
|
-
Enabled: true
|
173
|
-
Style/Sample:
|
174
|
-
Enabled: true
|
175
|
-
Style/StabbyLambdaParentheses:
|
32
|
+
Style/ClassAndModuleChildren:
|
176
33
|
Enabled: true
|
34
|
+
Exclude:
|
35
|
+
- test/**/*
|
36
|
+
Style/Documentation:
|
37
|
+
Enabled: false
|
38
|
+
Style/IfUnlessModifier:
|
39
|
+
Enabled: false
|
177
40
|
Style/StringLiterals:
|
178
41
|
Enabled: true
|
179
42
|
EnforcedStyle: double_quotes
|
43
|
+
Style/SymbolArray:
|
44
|
+
Enabled: false
|
data/Gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
gemspec
|
@@ -9,6 +11,8 @@ end
|
|
9
11
|
group :test do
|
10
12
|
gem "minitest", ">= 5"
|
11
13
|
gem "mocha"
|
12
|
-
gem "rubocop", "~>
|
14
|
+
gem "rubocop", "~> 1.37", require: false
|
15
|
+
gem "rubocop-minitest", require: false
|
13
16
|
gem "rubocop-performance", require: false
|
17
|
+
gem "rubocop-rake", require: false
|
14
18
|
end
|
data/README.md
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
A ruby client and throttling library for [Freno](https://github.com/github/freno): the cooperative, highly available throttler service.
|
1
|
+
A Ruby client and throttling library for [Freno](https://github.com/github/freno): the cooperative, highly available throttler service.
|
4
2
|
|
5
3
|
## Current status
|
6
4
|
|
@@ -177,7 +175,7 @@ end
|
|
177
175
|
|
178
176
|
### Throttler objects
|
179
177
|
|
180
|
-
Apart from the operations above, freno-client comes with `Freno::Throttler`, a
|
178
|
+
Apart from the operations above, freno-client comes with `Freno::Throttler`, a Ruby library for throttling. You can use it in the following way:
|
181
179
|
|
182
180
|
```ruby
|
183
181
|
require "freno/throttler"
|
data/Rakefile
CHANGED
data/freno-client.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "lib/freno/client/version"
|
2
4
|
|
3
5
|
Gem::Specification.new do |spec|
|
@@ -11,14 +13,16 @@ Gem::Specification.new do |spec|
|
|
11
13
|
freno-client is a Ruby library that interacts with Freno using HTTP.
|
12
14
|
Freno is a throttling service and its source code is available at
|
13
15
|
https://github.com/github/freno
|
14
|
-
|
16
|
+
DESC
|
15
17
|
|
16
18
|
spec.homepage = "https://github.com/github/freno-client"
|
17
19
|
spec.license = "MIT"
|
18
20
|
|
19
|
-
spec.required_ruby_version = ">= 2.
|
21
|
+
spec.required_ruby_version = ">= 2.7.0"
|
20
22
|
|
21
23
|
spec.files = `git ls-files -z`.split("\x0").grep_v(/^(bin|test)/)
|
22
24
|
|
23
|
-
spec.add_dependency "faraday", "
|
25
|
+
spec.add_dependency "faraday", "< 3"
|
26
|
+
|
27
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
24
28
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gemspec path: ".."
|
6
|
+
|
7
|
+
gem "faraday", "~> 0.0"
|
8
|
+
|
9
|
+
# Content below copied from Gemfile
|
10
|
+
|
11
|
+
group :development do
|
12
|
+
gem "rake"
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem "minitest", ">= 5"
|
17
|
+
gem "mocha"
|
18
|
+
gem "rubocop", "~> 1.37", require: false
|
19
|
+
gem "rubocop-minitest", require: false
|
20
|
+
gem "rubocop-performance", require: false
|
21
|
+
gem "rubocop-rake", require: false
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gemspec path: ".."
|
6
|
+
|
7
|
+
gem "faraday", "~> 1.0"
|
8
|
+
|
9
|
+
# Content below copied from Gemfile
|
10
|
+
|
11
|
+
group :development do
|
12
|
+
gem "rake"
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem "minitest", ">= 5"
|
17
|
+
gem "mocha"
|
18
|
+
gem "rubocop", "~> 1.37", require: false
|
19
|
+
gem "rubocop-minitest", require: false
|
20
|
+
gem "rubocop-performance", require: false
|
21
|
+
gem "rubocop-rake", require: false
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gemspec path: ".."
|
6
|
+
|
7
|
+
gem "faraday", "~> 2.0"
|
8
|
+
|
9
|
+
# Content below copied from Gemfile
|
10
|
+
|
11
|
+
group :development do
|
12
|
+
gem "rake"
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem "minitest", ">= 5"
|
17
|
+
gem "mocha"
|
18
|
+
gem "rubocop", "~> 1.37", require: false
|
19
|
+
gem "rubocop-minitest", require: false
|
20
|
+
gem "rubocop-performance", require: false
|
21
|
+
gem "rubocop-rake", require: false
|
22
|
+
end
|
data/lib/freno/client/errors.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Freno
|
2
4
|
class Client
|
3
5
|
module Preconditions
|
4
|
-
|
6
|
+
module_function
|
5
7
|
|
6
8
|
PreconditionNotMet = Class.new(ArgumentError)
|
7
9
|
|
@@ -21,7 +23,7 @@ module Freno
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def report
|
24
|
-
raise PreconditionNotMet
|
26
|
+
raise PreconditionNotMet, errors.join("\n") unless errors.empty?
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
data/lib/freno/client/request.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "preconditions"
|
2
4
|
require_relative "result"
|
3
5
|
require_relative "errors"
|
@@ -5,11 +7,9 @@ require_relative "errors"
|
|
5
7
|
module Freno
|
6
8
|
class Client
|
7
9
|
class Request
|
8
|
-
|
9
10
|
include Freno::Client::Preconditions
|
10
11
|
|
11
|
-
attr_reader :faraday, :args, :options
|
12
|
-
attr_reader :raise_on_timeout
|
12
|
+
attr_reader :faraday, :args, :options, :raise_on_timeout
|
13
13
|
|
14
14
|
def self.perform(**kwargs)
|
15
15
|
new(**kwargs).perform
|
@@ -18,7 +18,7 @@ module Freno
|
|
18
18
|
def initialize(**kwargs)
|
19
19
|
@args = kwargs
|
20
20
|
@faraday = kwargs.delete(:faraday) || nil
|
21
|
-
@options = kwargs.delete(:options) ||
|
21
|
+
@options = kwargs.delete(:options) || {}
|
22
22
|
|
23
23
|
@raise_on_timeout = options.fetch(:raise_on_timeout, true)
|
24
24
|
@verb = options.fetch(:verb, :head)
|
@@ -27,11 +27,12 @@ module Freno
|
|
27
27
|
def perform
|
28
28
|
response = request(verb, path, params)
|
29
29
|
process_response(response)
|
30
|
-
rescue Faraday::TimeoutError =>
|
31
|
-
raise Freno::Error
|
30
|
+
rescue Faraday::TimeoutError => error
|
31
|
+
raise Freno::Error, error if raise_on_timeout
|
32
|
+
|
32
33
|
Result.from_meaning(:request_timeout)
|
33
|
-
rescue =>
|
34
|
-
raise Freno::Error
|
34
|
+
rescue StandardError => error
|
35
|
+
raise Freno::Error, error
|
35
36
|
end
|
36
37
|
|
37
38
|
protected
|
data/lib/freno/client/result.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
|
3
5
|
module Freno
|
4
6
|
class Client
|
5
7
|
class Result
|
6
|
-
|
7
8
|
# https://github.com/github/freno/blob/master/doc/http.md#status-codes
|
8
9
|
FRENO_STATUS_CODE_MEANINGS = {
|
9
10
|
200 => :ok,
|
@@ -55,6 +56,7 @@ module Freno
|
|
55
56
|
|
56
57
|
def ==(other)
|
57
58
|
return meaning == other if other.is_a? Symbol
|
59
|
+
|
58
60
|
code == other
|
59
61
|
end
|
60
62
|
end
|
data/lib/freno/client/version.rb
CHANGED
data/lib/freno/client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "freno/client/version"
|
2
4
|
require "freno/client/requests/check_read"
|
3
5
|
require "freno/client/requests/check"
|
@@ -8,10 +10,10 @@ module Freno
|
|
8
10
|
class DecorationError < ArgumentError; end
|
9
11
|
|
10
12
|
REQUESTS = {
|
11
|
-
check:
|
12
|
-
check_read:
|
13
|
-
replication_delay: Requests::ReplicationDelay
|
14
|
-
}
|
13
|
+
check: Requests::Check,
|
14
|
+
check_read: Requests::CheckRead,
|
15
|
+
replication_delay: Requests::ReplicationDelay
|
16
|
+
}.freeze
|
15
17
|
|
16
18
|
attr_reader :faraday, :decorators, :decorated_requests
|
17
19
|
attr_accessor :default_app, :default_store_name, :default_store_type, :options
|
@@ -78,8 +80,21 @@ module Freno
|
|
78
80
|
#
|
79
81
|
# Returns Result
|
80
82
|
#
|
81
|
-
def check_read(
|
82
|
-
|
83
|
+
def check_read(
|
84
|
+
threshold:,
|
85
|
+
app: default_app,
|
86
|
+
store_type: default_store_type,
|
87
|
+
store_name: default_store_name,
|
88
|
+
options: {}
|
89
|
+
)
|
90
|
+
perform(
|
91
|
+
:check_read,
|
92
|
+
threshold: threshold,
|
93
|
+
app: app,
|
94
|
+
store_type: store_type,
|
95
|
+
store_name: store_name,
|
96
|
+
options: self.options.merge(options)
|
97
|
+
)
|
83
98
|
end
|
84
99
|
|
85
100
|
# Implements a specific check request to retrieve the consolidated replication
|
@@ -89,11 +104,21 @@ module Freno
|
|
89
104
|
#
|
90
105
|
# Returns Float indicating the replication delay in seconds as reported by Freno.
|
91
106
|
#
|
92
|
-
def replication_delay(
|
93
|
-
|
107
|
+
def replication_delay(
|
108
|
+
app: default_app,
|
109
|
+
store_type: default_store_type,
|
110
|
+
store_name: default_store_name,
|
111
|
+
options: {}
|
112
|
+
)
|
113
|
+
perform(
|
114
|
+
:replication_delay,
|
115
|
+
app: app,
|
116
|
+
store_type: store_type,
|
117
|
+
store_name: store_name,
|
118
|
+
options: self.options.merge(options)
|
119
|
+
)
|
94
120
|
end
|
95
121
|
|
96
|
-
|
97
122
|
# Determines whether Freno considers it"s OK to write to masters
|
98
123
|
#
|
99
124
|
# Returns true or false.
|
@@ -107,8 +132,20 @@ module Freno
|
|
107
132
|
#
|
108
133
|
# Returns true or false.
|
109
134
|
#
|
110
|
-
def check_read?(
|
111
|
-
|
135
|
+
def check_read?(
|
136
|
+
threshold:,
|
137
|
+
app: default_app,
|
138
|
+
store_type: default_store_type,
|
139
|
+
store_name: default_store_name,
|
140
|
+
options: {}
|
141
|
+
)
|
142
|
+
check_read(
|
143
|
+
threshold: threshold,
|
144
|
+
app: app,
|
145
|
+
store_type: store_type,
|
146
|
+
store_name: store_name,
|
147
|
+
options: self.options.merge(options)
|
148
|
+
).ok?
|
112
149
|
end
|
113
150
|
|
114
151
|
# Configures the client to extend the functionality of part or all the API
|
@@ -165,18 +202,20 @@ module Freno
|
|
165
202
|
# end
|
166
203
|
# ```
|
167
204
|
#
|
168
|
-
def decorate(
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
205
|
+
def decorate(request_or_all, with:)
|
206
|
+
requests =
|
207
|
+
if request_or_all == :all
|
208
|
+
REQUESTS.keys
|
209
|
+
else
|
210
|
+
Array(request_or_all)
|
211
|
+
end
|
174
212
|
|
213
|
+
with = Array(with)
|
175
214
|
validate!(with)
|
176
215
|
|
177
216
|
requests.each do |request|
|
178
217
|
decorators[request] ||= []
|
179
|
-
decorators[request] +=
|
218
|
+
decorators[request] += with
|
180
219
|
decorated_requests[request] = nil
|
181
220
|
end
|
182
221
|
end
|
@@ -194,7 +233,7 @@ module Freno
|
|
194
233
|
outermost = to_decorate[0]
|
195
234
|
current = outermost
|
196
235
|
|
197
|
-
(to_decorate[1
|
236
|
+
(to_decorate[1..]).each do |decorator|
|
198
237
|
current.request = decorator
|
199
238
|
current = current.request
|
200
239
|
end
|
@@ -206,6 +245,7 @@ module Freno
|
|
206
245
|
def validate!(decorators)
|
207
246
|
decorators.each do |decorator|
|
208
247
|
raise DecorationError, "Cannot reuse decorator instance: #{decorator}" if already_registered?(decorator)
|
248
|
+
|
209
249
|
registered_decorators << decorator
|
210
250
|
end
|
211
251
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Freno
|
2
4
|
class Throttler
|
3
|
-
|
4
5
|
# A CircuitBreaker is the entry point of the pattern with same name.
|
5
6
|
# (see https://martinfowler.com/bliki/CircuitBreaker.html)
|
6
7
|
#
|
@@ -14,7 +15,6 @@ module Freno
|
|
14
15
|
# next request is allowed.
|
15
16
|
#
|
16
17
|
module CircuitBreaker
|
17
|
-
|
18
18
|
# The Noop circuit breaker is the `:circuit_breaker` used by default in
|
19
19
|
# the Throttler
|
20
20
|
#
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Freno
|
2
4
|
class Throttler
|
3
|
-
|
4
5
|
# An Instrumenter is an object that responds to
|
5
6
|
# `instrument(event_name, payload = {})` to receive events from the
|
6
7
|
# throttler.
|
@@ -10,7 +11,6 @@ module Freno
|
|
10
11
|
# the application.
|
11
12
|
#
|
12
13
|
module Instrumenter
|
13
|
-
|
14
14
|
# The Noop instrumenter is the `:instrumenter` used by default in the
|
15
15
|
# Throttler
|
16
16
|
#
|
@@ -18,7 +18,7 @@ module Freno
|
|
18
18
|
# provided.
|
19
19
|
#
|
20
20
|
class Noop
|
21
|
-
def self.instrument(
|
21
|
+
def self.instrument(_event_name, payload = {})
|
22
22
|
yield payload if block_given?
|
23
23
|
end
|
24
24
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Freno
|
2
4
|
class Throttler
|
3
|
-
|
4
5
|
# A Mapper is any object that responds to `call`, by receiving a context
|
5
6
|
# object and returning a list of strings, each of which corresponds to the
|
6
7
|
# store_name that will be checked in freno.
|
@@ -13,7 +14,6 @@ module Freno
|
|
13
14
|
# where that shards exist.
|
14
15
|
#
|
15
16
|
module Mapper
|
16
|
-
|
17
17
|
# The Identity mapper is the one used by default in the Throttler.
|
18
18
|
#
|
19
19
|
# It works by informing the throttler to check exact same stores that it
|
data/lib/freno/throttler.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "freno/client"
|
2
4
|
require "freno/throttler/errors"
|
3
5
|
require "freno/throttler/mapper"
|
@@ -5,7 +7,6 @@ require "freno/throttler/instrumenter"
|
|
5
7
|
require "freno/throttler/circuit_breaker"
|
6
8
|
|
7
9
|
module Freno
|
8
|
-
|
9
10
|
# Freno::Throttler is the class responsible for throttling writes to a cluster
|
10
11
|
# or a set of clusters. Throttling means to slow down the pace at which write
|
11
12
|
# operations occur by checking with freno whether all the clusters affected by
|
@@ -32,9 +33,17 @@ module Freno
|
|
32
33
|
# and sleep if any of the stores is not ok.
|
33
34
|
#
|
34
35
|
class Throttler
|
35
|
-
|
36
36
|
DEFAULT_WAIT_SECONDS = 0.5
|
37
37
|
DEFAULT_MAX_WAIT_SECONDS = 10
|
38
|
+
REQUIRED_ARGS = %i[
|
39
|
+
client
|
40
|
+
app
|
41
|
+
mapper
|
42
|
+
instrumenter
|
43
|
+
circuit_breaker
|
44
|
+
wait_seconds
|
45
|
+
max_wait_seconds
|
46
|
+
].freeze
|
38
47
|
|
39
48
|
attr_accessor :client,
|
40
49
|
:app,
|
@@ -90,14 +99,15 @@ module Freno
|
|
90
99
|
# seconds the throttler will wait in total for replicas to catch-up
|
91
100
|
# before raising a `WaitedTooLong` error.
|
92
101
|
#
|
93
|
-
def initialize(
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
102
|
+
def initialize(
|
103
|
+
client: nil,
|
104
|
+
app: nil,
|
105
|
+
mapper: Mapper::Identity,
|
106
|
+
instrumenter: Instrumenter::Noop,
|
107
|
+
circuit_breaker: CircuitBreaker::Noop,
|
108
|
+
wait_seconds: DEFAULT_WAIT_SECONDS,
|
109
|
+
max_wait_seconds: DEFAULT_MAX_WAIT_SECONDS
|
110
|
+
)
|
101
111
|
@client = client
|
102
112
|
@app = app
|
103
113
|
@mapper = mapper
|
@@ -156,7 +166,7 @@ module Freno
|
|
156
166
|
instrument(:called, store_names: store_names)
|
157
167
|
waited = 0
|
158
168
|
|
159
|
-
|
169
|
+
loop do
|
160
170
|
unless circuit_breaker.allow_request?
|
161
171
|
instrument(:circuit_open, store_names: store_names, waited: waited)
|
162
172
|
raise CircuitOpen
|
@@ -172,11 +182,11 @@ module Freno
|
|
172
182
|
waited += wait_seconds
|
173
183
|
instrument(:waited, store_names: store_names, waited: waited, max: max_wait_seconds)
|
174
184
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
185
|
+
next unless waited > max_wait_seconds
|
186
|
+
|
187
|
+
instrument(:waited_too_long, store_names: store_names, waited: waited, max: max_wait_seconds)
|
188
|
+
circuit_breaker.failure
|
189
|
+
raise WaitedTooLong.new(waited_seconds: waited, max_wait_seconds: max_wait_seconds)
|
180
190
|
end
|
181
191
|
end
|
182
192
|
|
@@ -185,8 +195,7 @@ module Freno
|
|
185
195
|
def validate_args
|
186
196
|
errors = []
|
187
197
|
|
188
|
-
|
189
|
-
wait_seconds max_wait_seconds).each do |argument|
|
198
|
+
REQUIRED_ARGS.each do |argument|
|
190
199
|
errors << "#{argument} must be provided" unless send(argument)
|
191
200
|
end
|
192
201
|
|
@@ -194,17 +203,17 @@ module Freno
|
|
194
203
|
errors << "max_wait_seconds (#{max_wait_seconds}) has to be greather than wait_seconds (#{wait_seconds})"
|
195
204
|
end
|
196
205
|
|
197
|
-
raise ArgumentError
|
206
|
+
raise ArgumentError, errors.join("\n") if errors.any?
|
198
207
|
end
|
199
208
|
|
200
209
|
def all_stores_ok?(store_names, **options)
|
201
210
|
store_names.all? do |store_name|
|
202
211
|
client.check?(app: app, store_name: store_name, options: options)
|
203
212
|
end
|
204
|
-
rescue Freno::Error =>
|
205
|
-
instrument(:freno_errored, store_names: store_names, error:
|
213
|
+
rescue Freno::Error => error
|
214
|
+
instrument(:freno_errored, store_names: store_names, error: error)
|
206
215
|
circuit_breaker.failure
|
207
|
-
raise ClientError
|
216
|
+
raise ClientError, error
|
208
217
|
end
|
209
218
|
|
210
219
|
def wait
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: freno-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "<"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '3'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "<"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '3'
|
27
27
|
description: 'freno-client is a Ruby library that interacts with Freno using HTTP.
|
28
28
|
Freno is a throttling service and its source code is available at https://github.com/github/freno '
|
29
29
|
email: opensource+freno-client@github.com
|
@@ -31,9 +31,9 @@ executables: []
|
|
31
31
|
extensions: []
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
|
+
- ".github/workflows/ruby.yml"
|
34
35
|
- ".gitignore"
|
35
36
|
- ".rubocop.yml"
|
36
|
-
- ".travis.yml"
|
37
37
|
- CODE_OF_CONDUCT.md
|
38
38
|
- CONTRIBUTING.md
|
39
39
|
- Gemfile
|
@@ -41,6 +41,9 @@ files:
|
|
41
41
|
- README.md
|
42
42
|
- Rakefile
|
43
43
|
- freno-client.gemspec
|
44
|
+
- gemfiles/faraday_0.gemfile
|
45
|
+
- gemfiles/faraday_1.gemfile
|
46
|
+
- gemfiles/faraday_2.gemfile
|
44
47
|
- lib/freno/client.rb
|
45
48
|
- lib/freno/client/errors.rb
|
46
49
|
- lib/freno/client/preconditions.rb
|
@@ -58,7 +61,8 @@ files:
|
|
58
61
|
homepage: https://github.com/github/freno-client
|
59
62
|
licenses:
|
60
63
|
- MIT
|
61
|
-
metadata:
|
64
|
+
metadata:
|
65
|
+
rubygems_mfa_required: 'true'
|
62
66
|
post_install_message:
|
63
67
|
rdoc_options: []
|
64
68
|
require_paths:
|
@@ -67,14 +71,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
67
71
|
requirements:
|
68
72
|
- - ">="
|
69
73
|
- !ruby/object:Gem::Version
|
70
|
-
version: 2.
|
74
|
+
version: 2.7.0
|
71
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
76
|
requirements:
|
73
77
|
- - ">="
|
74
78
|
- !ruby/object:Gem::Version
|
75
79
|
version: '0'
|
76
80
|
requirements: []
|
77
|
-
rubygems_version: 3.
|
81
|
+
rubygems_version: 3.3.7
|
78
82
|
signing_key:
|
79
83
|
specification_version: 4
|
80
84
|
summary: A library for interacting with Freno, the throttler service
|