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 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