thrifter 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.
- checksums.yaml +4 -4
- data/Makefile +1 -1
- data/lib/thrifter.rb +7 -1
- data/lib/thrifter/extensions/retriable.rb +2 -0
- data/lib/thrifter/instrumented_pool.rb +36 -0
- data/lib/thrifter/middleware/client_metrics.rb +4 -0
- data/lib/thrifter/middleware/rpc_metrics.rb +4 -0
- data/lib/thrifter/version.rb +1 -1
- data/test/acceptance_test.rb +10 -2
- data/test/extensions/retry_test.rb +43 -0
- data/test/instrumented_pool_test.rb +117 -0
- data/test/middleware/client_metrics_test.rb +17 -0
- data/test/middleware/rpc_metrics_test.rb +17 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65d98aacd1ca9934a61d232bda0b67412571c0f6
|
4
|
+
data.tar.gz: a932dd7f6d35c006f4b82fbb1c1dcafa28fddb34
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46844d62766a667447c0138d60d07746a3d384f11586ff524eda5743de9d1ed804433de8bd18e00bc790c0e7f1493452facecc3c7bc764a58b1a58d14da819bc
|
7
|
+
data.tar.gz: 75b6e393f98b6c0bb4741db90c0663f9d8bbba43f9075035056fd9c912f7f74ac00bb999aa8ab21469ea041869ed1de6ffb9ab75e26f2f593d965f04a378e851
|
data/Makefile
CHANGED
data/lib/thrifter.rb
CHANGED
@@ -33,6 +33,10 @@ module Thrifter
|
|
33
33
|
def increment(*)
|
34
34
|
|
35
35
|
end
|
36
|
+
|
37
|
+
def gauge(*)
|
38
|
+
|
39
|
+
end
|
36
40
|
end
|
37
41
|
|
38
42
|
RESERVED_METHODS = [
|
@@ -148,7 +152,7 @@ module Thrifter
|
|
148
152
|
fail ArgumentError, 'URI did not contain port' unless @uri.port
|
149
153
|
end
|
150
154
|
|
151
|
-
@pool =
|
155
|
+
@pool = InstrumentedPool.new(statsd: config.statsd, size: config.pool_size.to_i, timeout: config.pool_timeout.to_f) do
|
152
156
|
stack = MiddlewareStack.new
|
153
157
|
|
154
158
|
stack.use config.stack
|
@@ -191,6 +195,8 @@ module Thrifter
|
|
191
195
|
end
|
192
196
|
end
|
193
197
|
|
198
|
+
require_relative 'thrifter/instrumented_pool'
|
199
|
+
|
194
200
|
require_relative 'thrifter/extensions/ping'
|
195
201
|
require_relative 'thrifter/extensions/retriable'
|
196
202
|
|
@@ -41,9 +41,11 @@ module Thrifter
|
|
41
41
|
client.send name, *args
|
42
42
|
rescue *retriable => ex
|
43
43
|
if counter < tries
|
44
|
+
config.statsd.increment("rpc.#{name}.retry")
|
44
45
|
sleep interval
|
45
46
|
retry
|
46
47
|
else
|
48
|
+
config.statsd.increment("rpc.#{name}.retry")
|
47
49
|
raise RetryError.new(tries, name, ex)
|
48
50
|
end
|
49
51
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Thrifter
|
2
|
+
class InstrumentedPool < ConnectionPool
|
3
|
+
attr_reader :statsd
|
4
|
+
|
5
|
+
def initialize(options = { }, &block)
|
6
|
+
super(options, &block)
|
7
|
+
@statsd = options.fetch(:statsd)
|
8
|
+
end
|
9
|
+
|
10
|
+
def checkout(*args)
|
11
|
+
statsd.gauge('thread_pool.size', @size)
|
12
|
+
statsd.time('thread_pool.latency') do
|
13
|
+
super.tap do |conn|
|
14
|
+
statsd.increment('thread_pool.checkout')
|
15
|
+
statsd.gauge('thread_pool.in_use', in_use)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
rescue Timeout::Error => ex
|
19
|
+
statsd.increment('thread_pool.timeout')
|
20
|
+
raise ex
|
21
|
+
end
|
22
|
+
|
23
|
+
def checkin(*args)
|
24
|
+
super.tap do
|
25
|
+
statsd.increment('thread_pool.checkin')
|
26
|
+
statsd.gauge('thread_pool.in_use', in_use)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def in_use
|
33
|
+
(1 - (@available.length / @size.to_f)).round(2)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -28,6 +28,10 @@ module Thrifter
|
|
28
28
|
statsd.increment 'rpc.error'
|
29
29
|
statsd.increment 'rpc.error.timeout'
|
30
30
|
raise ex
|
31
|
+
rescue Thrifter::RetryError => ex
|
32
|
+
statsd.increment 'rpc.error'
|
33
|
+
statsd.increment 'rpc.error.retry'
|
34
|
+
raise ex
|
31
35
|
rescue => ex
|
32
36
|
statsd.increment 'rpc.error'
|
33
37
|
statsd.increment 'rpc.error.other'
|
@@ -77,6 +77,10 @@ module Thrifter
|
|
77
77
|
statsd.increment "rpc.#{rpc.name}.error"
|
78
78
|
statsd.increment "rpc.#{rpc.name}.error.timeout"
|
79
79
|
raise ex
|
80
|
+
rescue Thrifter::RetryError => ex
|
81
|
+
statsd.increment "rpc.#{rpc.name}.error"
|
82
|
+
statsd.increment "rpc.#{rpc.name}.error.retry"
|
83
|
+
raise ex
|
80
84
|
rescue => ex
|
81
85
|
statsd.increment "rpc.#{rpc.name}.error"
|
82
86
|
statsd.increment "rpc.#{rpc.name}.error.other"
|
data/lib/thrifter/version.rb
CHANGED
data/test/acceptance_test.rb
CHANGED
@@ -99,7 +99,11 @@ class AcceptanceTest < MiniTest::Unit::TestCase
|
|
99
99
|
config.pool_timeout = 75
|
100
100
|
end
|
101
101
|
|
102
|
-
|
102
|
+
Thrifter::InstrumentedPool.expects(:new).with({
|
103
|
+
statsd: client.config.statsd,
|
104
|
+
size: 50,
|
105
|
+
timeout: 75
|
106
|
+
})
|
103
107
|
|
104
108
|
client.new
|
105
109
|
end
|
@@ -111,7 +115,11 @@ class AcceptanceTest < MiniTest::Unit::TestCase
|
|
111
115
|
config.pool_timeout = '75.5'
|
112
116
|
end
|
113
117
|
|
114
|
-
|
118
|
+
Thrifter::InstrumentedPool.expects(:new).with({
|
119
|
+
statsd: client.config.statsd,
|
120
|
+
size: 50,
|
121
|
+
timeout: 75.5
|
122
|
+
})
|
115
123
|
|
116
124
|
client.new
|
117
125
|
end
|
@@ -14,10 +14,41 @@ class RetryTest < MiniTest::Unit::TestCase
|
|
14
14
|
config.transport = FakeTransport
|
15
15
|
end
|
16
16
|
|
17
|
+
class TestStatsd
|
18
|
+
attr_reader :counters
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@counters = [ ]
|
22
|
+
end
|
23
|
+
|
24
|
+
def increment(counter)
|
25
|
+
@counters << counter
|
26
|
+
end
|
27
|
+
|
28
|
+
def time(*args)
|
29
|
+
yield
|
30
|
+
end
|
31
|
+
|
32
|
+
def gauge(*)
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :statsd
|
38
|
+
|
17
39
|
def known_errors
|
18
40
|
Thrifter::Retry::DEFAULT_RETRIABLE_ERRORS
|
19
41
|
end
|
20
42
|
|
43
|
+
def setup
|
44
|
+
super
|
45
|
+
@statsd = TestStatsd.new
|
46
|
+
|
47
|
+
RetryClient.configure do |config|
|
48
|
+
config.statsd = statsd
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
21
52
|
def test_does_not_retry_on_unexpected_errors
|
22
53
|
thrift_client = mock
|
23
54
|
thrift_client.expects(:echo).with(:request).raises(JunkError)
|
@@ -42,6 +73,12 @@ class RetryTest < MiniTest::Unit::TestCase
|
|
42
73
|
result = client.with_retry({ tries: 2, interval: 0.01 }).echo(:request)
|
43
74
|
|
44
75
|
assert :response == result, 'return value incorrect'
|
76
|
+
|
77
|
+
counters = statsd.counters.count do |item|
|
78
|
+
item == 'rpc.echo.retry'
|
79
|
+
end
|
80
|
+
|
81
|
+
assert_equal 1, counters, 'Retry not counted'
|
45
82
|
end
|
46
83
|
|
47
84
|
def test_retries_on_exceptions_specified_explicitly
|
@@ -88,6 +125,12 @@ class RetryTest < MiniTest::Unit::TestCase
|
|
88
125
|
assert_match /5/, error.message, 'Error not descriptive'
|
89
126
|
assert_match /echo/, error.message, 'Error not descriptive'
|
90
127
|
assert_match /#{err.to_s}/, error.message, 'Missing error details'
|
128
|
+
|
129
|
+
counters = statsd.counters.count do |item|
|
130
|
+
item == 'rpc.echo.retry'
|
131
|
+
end
|
132
|
+
|
133
|
+
assert_equal 5, counters, 'Retry not counted'
|
91
134
|
end
|
92
135
|
|
93
136
|
def test_retries_on_application_exception
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class InstrumentedPoolTest < MiniTest::Unit::TestCase
|
4
|
+
class TestStatsd
|
5
|
+
attr_reader :timers, :gauges, :counters
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@timers = [ ]
|
9
|
+
@gauges = [ ]
|
10
|
+
@counters = [ ]
|
11
|
+
end
|
12
|
+
|
13
|
+
def clear
|
14
|
+
timers.clear
|
15
|
+
gauges.clear
|
16
|
+
counters.clear
|
17
|
+
end
|
18
|
+
|
19
|
+
def time(key)
|
20
|
+
timers << key
|
21
|
+
yield
|
22
|
+
end
|
23
|
+
|
24
|
+
def increment(key, value = 1)
|
25
|
+
counters << [ key, value ]
|
26
|
+
end
|
27
|
+
|
28
|
+
def gauge(key, value)
|
29
|
+
gauges << [ key, value ]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class TimeoutPool < Thrifter::InstrumentedPool
|
34
|
+
class FakeStack
|
35
|
+
def pop(*args)
|
36
|
+
raise Timeout::Error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(*args, &block)
|
41
|
+
super(*args) { :placeholder }
|
42
|
+
@available = FakeStack.new
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :pool, :statsd
|
47
|
+
|
48
|
+
def setup
|
49
|
+
super
|
50
|
+
|
51
|
+
@statsd = TestStatsd.new
|
52
|
+
@pool = Thrifter::InstrumentedPool.new(size: 5, timeout: 5, statsd: statsd) do
|
53
|
+
:foo
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_checkout_instrumentation
|
58
|
+
assert_equal :foo, pool.checkout, 'Incorrect connection'
|
59
|
+
|
60
|
+
latency = statsd.timers.first
|
61
|
+
assert latency
|
62
|
+
assert_equal 'thread_pool.latency', latency
|
63
|
+
|
64
|
+
counter = statsd.counters[0]
|
65
|
+
assert counter
|
66
|
+
assert_equal 'thread_pool.checkout', counter[0]
|
67
|
+
assert_equal 1, counter[1]
|
68
|
+
|
69
|
+
size = statsd.gauges[0]
|
70
|
+
assert size
|
71
|
+
assert_equal 'thread_pool.size', size[0]
|
72
|
+
assert_equal 5, size[1]
|
73
|
+
|
74
|
+
in_use = statsd.gauges[1]
|
75
|
+
assert in_use
|
76
|
+
assert_equal 'thread_pool.in_use', in_use[0]
|
77
|
+
assert_equal 0.2, in_use[1]
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_checkin_instrumentation
|
81
|
+
assert pool.checkout
|
82
|
+
statsd.clear
|
83
|
+
|
84
|
+
pool.checkin
|
85
|
+
|
86
|
+
counter = statsd.counters[0]
|
87
|
+
assert counter
|
88
|
+
assert_equal 'thread_pool.checkin', counter[0]
|
89
|
+
assert_equal 1, counter[1]
|
90
|
+
|
91
|
+
in_use = statsd.gauges.first
|
92
|
+
assert in_use
|
93
|
+
assert_equal 'thread_pool.in_use', in_use[0]
|
94
|
+
assert_equal 0.0, in_use[1]
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_checkout_timeout_instrumentation
|
98
|
+
@pool = TimeoutPool.new({
|
99
|
+
statsd: statsd,
|
100
|
+
size: 5,
|
101
|
+
timeout: 5
|
102
|
+
})
|
103
|
+
|
104
|
+
assert_raises Timeout::Error do
|
105
|
+
pool.checkout
|
106
|
+
end
|
107
|
+
|
108
|
+
latency = statsd.timers.first
|
109
|
+
assert latency
|
110
|
+
assert_equal 'thread_pool.latency', latency
|
111
|
+
|
112
|
+
counter = statsd.counters.first
|
113
|
+
assert counter
|
114
|
+
assert_equal 'thread_pool.timeout', counter[0]
|
115
|
+
assert_equal 1, counter[1]
|
116
|
+
end
|
117
|
+
end
|
@@ -92,6 +92,23 @@ class ClientMetricsTest < MiniTest::Unit::TestCase
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
+
def test_counts_retry_failures
|
96
|
+
app = stub
|
97
|
+
app.stubs(:call).with(rpc).raises(Thrifter::RetryError.new(1, 'echo', StandardError.new))
|
98
|
+
|
99
|
+
statsd = mock
|
100
|
+
statsd.expects(:time).yields
|
101
|
+
statsd.expects(:increment).with("rpc.error")
|
102
|
+
statsd.expects(:increment).with("rpc.outgoing")
|
103
|
+
statsd.expects(:increment).with("rpc.error.retry")
|
104
|
+
|
105
|
+
middleware = Thrifter::ClientMetrics.new app, statsd
|
106
|
+
|
107
|
+
assert_raises Thrifter::RetryError do
|
108
|
+
middleware.call rpc
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
95
112
|
def test_counts_other_errors
|
96
113
|
app = stub
|
97
114
|
app.stubs(:call).with(rpc).raises(StandardError)
|
@@ -478,6 +478,23 @@ class RpcMetricsTest < MiniTest::Unit::TestCase
|
|
478
478
|
end
|
479
479
|
end
|
480
480
|
|
481
|
+
def test_counts_retry_failures
|
482
|
+
app = stub
|
483
|
+
app.stubs(:call).with(rpc).raises(Thrifter::RetryError.new(1, 'echo', StandardError.new))
|
484
|
+
|
485
|
+
statsd = mock
|
486
|
+
statsd.expects(:time).yields
|
487
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.retry")
|
488
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
489
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
490
|
+
|
491
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
492
|
+
|
493
|
+
assert_raises Thrifter::RetryError do
|
494
|
+
middleware.call rpc
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
481
498
|
def test_counts_other_errors
|
482
499
|
app = stub
|
483
500
|
app.stubs(:call).with(rpc).raises(StandardError)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thrifter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ahawkins
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thrift
|
@@ -227,6 +227,7 @@ files:
|
|
227
227
|
- lib/thrifter/extensions/ping.rb
|
228
228
|
- lib/thrifter/extensions/queueing.rb
|
229
229
|
- lib/thrifter/extensions/retriable.rb
|
230
|
+
- lib/thrifter/instrumented_pool.rb
|
230
231
|
- lib/thrifter/middleware/client_metrics.rb
|
231
232
|
- lib/thrifter/middleware/error_wrapping.rb
|
232
233
|
- lib/thrifter/middleware/rpc_metrics.rb
|
@@ -239,6 +240,7 @@ files:
|
|
239
240
|
- test/extensions/ping_test.rb
|
240
241
|
- test/extensions/queueing_test.rb
|
241
242
|
- test/extensions/retry_test.rb
|
243
|
+
- test/instrumented_pool_test.rb
|
242
244
|
- test/middleware/client_metrics_test.rb
|
243
245
|
- test/middleware/error_wrapping_test.rb
|
244
246
|
- test/middleware/rpc_metrics_test.rb
|
@@ -277,6 +279,7 @@ test_files:
|
|
277
279
|
- test/extensions/ping_test.rb
|
278
280
|
- test/extensions/queueing_test.rb
|
279
281
|
- test/extensions/retry_test.rb
|
282
|
+
- test/instrumented_pool_test.rb
|
280
283
|
- test/middleware/client_metrics_test.rb
|
281
284
|
- test/middleware/error_wrapping_test.rb
|
282
285
|
- test/middleware/rpc_metrics_test.rb
|