thrifter 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d7eda9c8d9e79e117d147b9e6bca186d85c538dc
4
- data.tar.gz: b00587a8f32c3690c68f504343b4a650026d0299
3
+ metadata.gz: 65d98aacd1ca9934a61d232bda0b67412571c0f6
4
+ data.tar.gz: a932dd7f6d35c006f4b82fbb1c1dcafa28fddb34
5
5
  SHA512:
6
- metadata.gz: ad10cce350e1a4f0690c39aec5f80cdefa40415309ec19162bdfbd410be8d40bd2af861628215e8de6946271c7e1b945b9eab815722e647b2bb82177fba11e0c
7
- data.tar.gz: a156b72b2740ea7f145c5add008ead3212483484ad2020b4e47e3e02ef7b911dfcea0fc9095f7386c81e1a612750f9d11ed52059babe339cde0327183deea041
6
+ metadata.gz: 46844d62766a667447c0138d60d07746a3d384f11586ff524eda5743de9d1ed804433de8bd18e00bc790c0e7f1493452facecc3c7bc764a58b1a58d14da819bc
7
+ data.tar.gz: 75b6e393f98b6c0bb4741db90c0663f9d8bbba43f9075035056fd9c912f7f74ac00bb999aa8ab21469ea041869ed1de6ffb9ab75e26f2f593d965f04a378e851
data/Makefile CHANGED
@@ -20,7 +20,7 @@ $(THRIFT): test.thrift
20
20
  $(DOCKER_IMAGES):
21
21
  mkdir -p $(@D)
22
22
  touch $@
23
-
23
+
24
24
  $(BUNDLE): Dockerfile thrifter.gemspec $(DOCKER_IMAGES)
25
25
  docker build -t $(BUNDLE_IMAGE) .
26
26
  docker inspect -f '{{ .Id }}' $(BUNDLE_IMAGE) >> $(DOCKER_IMAGES)
@@ -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 = ConnectionPool.new size: config.pool_size.to_i, timeout: config.pool_timeout.to_f do
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"
@@ -1,3 +1,3 @@
1
1
  module Thrifter
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -99,7 +99,11 @@ class AcceptanceTest < MiniTest::Unit::TestCase
99
99
  config.pool_timeout = 75
100
100
  end
101
101
 
102
- ConnectionPool.expects(:new).with(size: 50, timeout: 75)
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
- ConnectionPool.expects(:new).with(size: 50, timeout: 75.5)
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.0.0
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-05-29 00:00:00.000000000 Z
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