thrifter 0.1.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -7
- data/lib/thrifter.rb +25 -9
- data/lib/thrifter/extensions/retriable.rb +14 -10
- data/lib/thrifter/middleware/client_metrics.rb +37 -0
- data/lib/thrifter/middleware/error_wrapping.rb +0 -4
- data/lib/thrifter/middleware/rpc_metrics.rb +86 -0
- data/lib/thrifter/version.rb +1 -1
- data/test/acceptance_test.rb +45 -7
- data/test/extensions/retry_test.rb +38 -2
- data/test/middleware/{metrics_test.rb → client_metrics_test.rb} +26 -14
- data/test/middleware/rpc_metrics_test.rb +497 -0
- data/test/test_helper.rb +4 -0
- data/thrifter.gemspec +2 -2
- metadata +14 -11
- data/lib/thrifter/middleware/metrics.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7eda9c8d9e79e117d147b9e6bca186d85c538dc
|
4
|
+
data.tar.gz: b00587a8f32c3690c68f504343b4a650026d0299
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad10cce350e1a4f0690c39aec5f80cdefa40415309ec19162bdfbd410be8d40bd2af861628215e8de6946271c7e1b945b9eab815722e647b2bb82177fba11e0c
|
7
|
+
data.tar.gz: a156b72b2740ea7f145c5add008ead3212483484ad2020b4e47e3e02ef7b911dfcea0fc9095f7386c81e1a612750f9d11ed52059babe339cde0327183deea041
|
data/README.md
CHANGED
@@ -30,7 +30,7 @@ Or install it yourself as:
|
|
30
30
|
|
31
31
|
## Usage
|
32
32
|
|
33
|
-
`
|
33
|
+
`Thrifter` is a factory (similar to `DelegateClass`) for building
|
34
34
|
client classes. It can be used like `DelegateClass` or like `Struct`.
|
35
35
|
The result is subclasses of `Thrifter::Client`. The classes use the
|
36
36
|
same methods to make RPCs. For example if the thrift service has a
|
@@ -42,7 +42,7 @@ RPC. Here are some examples.
|
|
42
42
|
ServiceClient = Thrifter.build(MyService::Client)
|
43
43
|
|
44
44
|
The struct style take a block as well
|
45
|
-
ServiceClient =
|
45
|
+
ServiceClient = Thrifter.build(MyService::Client) do
|
46
46
|
def custom_method(args)
|
47
47
|
# something something
|
48
48
|
end
|
@@ -65,7 +65,7 @@ production vs test). All settings are documented below. `uri` is the
|
|
65
65
|
most important! It must be set to instantiate clients.
|
66
66
|
|
67
67
|
```ruby
|
68
|
-
class MyClient <
|
68
|
+
class MyClient < Thrifter.build(MyService::Client)
|
69
69
|
# Thrift specific things
|
70
70
|
config.transport = Thrift::FramedTransport
|
71
71
|
config.protocol = Thrift::BinaryTransport
|
@@ -76,6 +76,7 @@ class MyClient < Thrifer.build(MyService::Client)
|
|
76
76
|
|
77
77
|
# Network Settings
|
78
78
|
config.rpc_timeout = 0.15
|
79
|
+
config.keep_alive = true
|
79
80
|
|
80
81
|
# Required to instantiate the client!
|
81
82
|
config.uri = 'tcp://foo:2383'
|
@@ -168,15 +169,15 @@ solution for different use cases.
|
|
168
169
|
#### Pinging
|
169
170
|
|
170
171
|
Components in a system may need to inquire if other systems are
|
171
|
-
available before continuing. `
|
172
|
+
available before continuing. `Thrifter::Ping` is just that.
|
172
173
|
`Thrifter::Ping` assumes the service has a `ping` RPC. If your
|
173
174
|
service does not have one (or is named differently) simply implement
|
174
175
|
the `ping` method on the class. Any successful response will count as
|
175
176
|
up, anything else will not.
|
176
177
|
|
177
178
|
```ruby
|
178
|
-
class MyService <
|
179
|
-
include
|
179
|
+
class MyService < Thrifter.build(MyService::Client)
|
180
|
+
include Thrifter::Ping
|
180
181
|
|
181
182
|
# Define a ping method if the service does not have one
|
182
183
|
def ping
|
@@ -215,7 +216,7 @@ middleware in whatever code configurres that environment. Only static
|
|
215
216
|
middleware should be configured directly in the class itself.
|
216
217
|
|
217
218
|
A middleware must implement the `call` method and accept at least one
|
218
|
-
argument to `initialize`. The `call` method recieves a `
|
219
|
+
argument to `initialize`. The `call` method recieves a `Thrifter::RPC`.
|
219
220
|
`Thrifter::RPC` is a sipmle struct with a `name` and `args` methods.
|
220
221
|
Here's an example:
|
221
222
|
|
data/lib/thrifter.rb
CHANGED
@@ -12,6 +12,10 @@ require 'middleware'
|
|
12
12
|
require 'connection_pool'
|
13
13
|
|
14
14
|
module Thrifter
|
15
|
+
ClientError = Tnt.boom do |ex|
|
16
|
+
"#{ex.class}: #{ex.message}"
|
17
|
+
end
|
18
|
+
|
15
19
|
RPC = Struct.new(:name, :args)
|
16
20
|
|
17
21
|
class MiddlewareStack < Middleware::Builder
|
@@ -40,6 +44,7 @@ module Thrifter
|
|
40
44
|
Configuration = Struct.new :transport, :protocol,
|
41
45
|
:pool_size, :pool_timeout,
|
42
46
|
:uri, :rpc_timeout,
|
47
|
+
:keep_alive,
|
43
48
|
:stack, :statsd
|
44
49
|
|
45
50
|
class << self
|
@@ -76,13 +81,21 @@ module Thrifter
|
|
76
81
|
|
77
82
|
class Client
|
78
83
|
class Dispatcher
|
79
|
-
|
84
|
+
attr_reader :app, :transport, :client, :config
|
85
|
+
|
86
|
+
def initialize(app, transport, client, config)
|
87
|
+
@app, @transport, @client, @config = app, transport, client, config
|
88
|
+
end
|
80
89
|
|
81
90
|
def call(rpc)
|
82
|
-
transport.open
|
83
|
-
|
84
|
-
|
91
|
+
transport.open unless transport.open?
|
92
|
+
|
93
|
+
client.send(rpc.name, *rpc.args).tap do
|
94
|
+
transport.close unless config.keep_alive
|
95
|
+
end
|
96
|
+
rescue => ex
|
85
97
|
transport.close
|
98
|
+
raise ex
|
86
99
|
end
|
87
100
|
end
|
88
101
|
|
@@ -114,11 +127,12 @@ module Thrifter
|
|
114
127
|
def inherited(base)
|
115
128
|
base.config = Configuration.new
|
116
129
|
base.configure do |config|
|
130
|
+
config.keep_alive = true
|
117
131
|
config.transport = Thrift::FramedTransport
|
118
132
|
config.protocol = Thrift::BinaryProtocol
|
119
133
|
config.pool_size = 12
|
120
|
-
config.pool_timeout =
|
121
|
-
config.rpc_timeout =
|
134
|
+
config.pool_timeout = 2
|
135
|
+
config.rpc_timeout = 2
|
122
136
|
config.statsd = NullStatsd.new
|
123
137
|
config.stack = MiddlewareStack.new
|
124
138
|
end
|
@@ -142,7 +156,8 @@ module Thrifter
|
|
142
156
|
# Insert metrics here so metrics are as close to the network
|
143
157
|
# as possible. This excludes time in any middleware an
|
144
158
|
# application may have configured.
|
145
|
-
stack.use
|
159
|
+
stack.use ClientMetrics, config.statsd
|
160
|
+
stack.use RpcMetrics, config.statsd
|
146
161
|
|
147
162
|
if client
|
148
163
|
stack.use DirectDispatcher, client
|
@@ -151,7 +166,7 @@ module Thrifter
|
|
151
166
|
transport = config.transport.new socket
|
152
167
|
protocol = config.protocol.new transport
|
153
168
|
|
154
|
-
stack.use Dispatcher, transport, client_class.new(protocol)
|
169
|
+
stack.use Dispatcher, transport, client_class.new(protocol), config
|
155
170
|
end
|
156
171
|
|
157
172
|
stack.finalize!
|
@@ -181,4 +196,5 @@ require_relative 'thrifter/extensions/retriable'
|
|
181
196
|
|
182
197
|
require_relative 'thrifter/middleware/error_wrapping'
|
183
198
|
require_relative 'thrifter/middleware/validation'
|
184
|
-
require_relative 'thrifter/middleware/
|
199
|
+
require_relative 'thrifter/middleware/client_metrics'
|
200
|
+
require_relative 'thrifter/middleware/rpc_metrics'
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module Thrifter
|
2
|
-
RetryError = Tnt.boom do |count, rpc|
|
3
|
-
"#{rpc} RPC unsuccessful after #{count} times"
|
2
|
+
RetryError = Tnt.boom do |count, rpc, exception|
|
3
|
+
"#{rpc} RPC unsuccessful after #{count} times. #{exception.class}: #{exception.message}"
|
4
4
|
end
|
5
5
|
|
6
6
|
module Retry
|
7
|
-
|
7
|
+
DEFAULT_RETRIABLE_ERRORS = [
|
8
|
+
ClientError,
|
8
9
|
Thrift::TransportException,
|
9
10
|
Thrift::ProtocolException,
|
10
11
|
Thrift::ApplicationException,
|
@@ -17,10 +18,13 @@ module Thrifter
|
|
17
18
|
]
|
18
19
|
|
19
20
|
class Proxy < BasicObject
|
20
|
-
attr_reader :tries, :interval, :client
|
21
|
+
attr_reader :tries, :interval, :client, :retriable
|
21
22
|
|
22
|
-
def initialize(client, tries, interval)
|
23
|
-
@client
|
23
|
+
def initialize(client, tries, interval, retriable)
|
24
|
+
@client = client
|
25
|
+
@tries = tries
|
26
|
+
@interval = interval
|
27
|
+
@retriable = DEFAULT_RETRIABLE_ERRORS + Array(retriable)
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
@@ -35,19 +39,19 @@ module Thrifter
|
|
35
39
|
begin
|
36
40
|
counter = counter + 1
|
37
41
|
client.send name, *args
|
38
|
-
rescue *
|
42
|
+
rescue *retriable => ex
|
39
43
|
if counter < tries
|
40
44
|
sleep interval
|
41
45
|
retry
|
42
46
|
else
|
43
|
-
raise RetryError.new(tries, name)
|
47
|
+
raise RetryError.new(tries, name, ex)
|
44
48
|
end
|
45
49
|
end
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
49
|
-
def with_retry(tries: 5, interval: 0.01)
|
50
|
-
proxy = Proxy.new self, tries, interval
|
53
|
+
def with_retry(tries: 5, interval: 0.01, retriable: [ ])
|
54
|
+
proxy = Proxy.new self, tries, interval, retriable
|
51
55
|
yield proxy if block_given?
|
52
56
|
proxy
|
53
57
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Thrifter
|
2
|
+
class ClientMetrics
|
3
|
+
include Concord.new(:app, :statsd)
|
4
|
+
|
5
|
+
def call(rpc)
|
6
|
+
statsd.increment 'rpc.outgoing'
|
7
|
+
|
8
|
+
response = statsd.time "rpc.latency" do #{rpc.name do
|
9
|
+
app.call rpc
|
10
|
+
end
|
11
|
+
|
12
|
+
statsd.increment 'rpc.success'
|
13
|
+
|
14
|
+
response
|
15
|
+
rescue Thrift::TransportException => ex
|
16
|
+
statsd.increment 'rpc.error'
|
17
|
+
statsd.increment 'rpc.error.transport'
|
18
|
+
raise ex
|
19
|
+
rescue Thrift::ProtocolException => ex
|
20
|
+
statsd.increment 'rpc.error'
|
21
|
+
statsd.increment 'rpc.error.protocol'
|
22
|
+
raise ex
|
23
|
+
rescue Thrift::ApplicationException => ex
|
24
|
+
statsd.increment 'rpc.error'
|
25
|
+
statsd.increment 'rpc.error.application'
|
26
|
+
raise ex
|
27
|
+
rescue Timeout::Error => ex
|
28
|
+
statsd.increment 'rpc.error'
|
29
|
+
statsd.increment 'rpc.error.timeout'
|
30
|
+
raise ex
|
31
|
+
rescue => ex
|
32
|
+
statsd.increment 'rpc.error'
|
33
|
+
statsd.increment 'rpc.error.other'
|
34
|
+
raise ex
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Thrifter
|
2
|
+
class RpcMetrics
|
3
|
+
include Concord.new(:app, :statsd)
|
4
|
+
|
5
|
+
def call(rpc)
|
6
|
+
statsd.increment "rpc.#{rpc.name}.outgoing"
|
7
|
+
|
8
|
+
response = statsd.time "rpc.#{rpc.name}.latency" do
|
9
|
+
app.call rpc
|
10
|
+
end
|
11
|
+
|
12
|
+
statsd.increment "rpc.#{rpc.name}.success"
|
13
|
+
|
14
|
+
response
|
15
|
+
rescue Thrift::TransportException => ex
|
16
|
+
statsd.increment "rpc.#{rpc.name}.error"
|
17
|
+
case ex.type
|
18
|
+
when Thrift::TransportException::UNKNOWN
|
19
|
+
statsd.increment "rpc.#{rpc.name}.error.transport.unknown"
|
20
|
+
when Thrift::TransportException::NOT_OPEN
|
21
|
+
statsd.increment "rpc.#{rpc.name}.error.transport.not_open"
|
22
|
+
when Thrift::TransportException::ALREADY_OPEN
|
23
|
+
statsd.increment "rpc.#{rpc.name}.error.transport.already_open"
|
24
|
+
when Thrift::TransportException::TIMED_OUT
|
25
|
+
statsd.increment "rpc.#{rpc.name}.error.transport.timeout"
|
26
|
+
when Thrift::TransportException::END_OF_FILE
|
27
|
+
statsd.increment "rpc.#{rpc.name}.error.transport.eof"
|
28
|
+
end
|
29
|
+
raise ex
|
30
|
+
rescue Thrift::ProtocolException => ex
|
31
|
+
statsd.increment "rpc.#{rpc.name}.error"
|
32
|
+
case ex.type
|
33
|
+
when Thrift::ProtocolException::UNKNOWN
|
34
|
+
statsd.increment "rpc.#{rpc.name}.error.protocol.unknown"
|
35
|
+
when Thrift::ProtocolException::INVALID_DATA
|
36
|
+
statsd.increment "rpc.#{rpc.name}.error.protocol.invalid_data"
|
37
|
+
when Thrift::ProtocolException::NEGATIVE_SIZE
|
38
|
+
statsd.increment "rpc.#{rpc.name}.error.protocol.negative_size"
|
39
|
+
when Thrift::ProtocolException::SIZE_LIMIT
|
40
|
+
statsd.increment "rpc.#{rpc.name}.error.protocol.size_limit"
|
41
|
+
when Thrift::ProtocolException::BAD_VERSION
|
42
|
+
statsd.increment "rpc.#{rpc.name}.error.protocol.bad_version"
|
43
|
+
when Thrift::ProtocolException::NOT_IMPLEMENTED
|
44
|
+
statsd.increment "rpc.#{rpc.name}.error.protocol.not_implemented"
|
45
|
+
when Thrift::ProtocolException::DEPTH_LIMIT
|
46
|
+
statsd.increment "rpc.#{rpc.name}.error.protocol.depth_limit"
|
47
|
+
end
|
48
|
+
raise ex
|
49
|
+
rescue Thrift::ApplicationException => ex
|
50
|
+
statsd.increment "rpc.#{rpc.name}.error"
|
51
|
+
case ex.type
|
52
|
+
when Thrift::ApplicationException::UNKNOWN
|
53
|
+
statsd.increment "rpc.#{rpc.name}.error.application.unknown"
|
54
|
+
when Thrift::ApplicationException::UNKNOWN_METHOD
|
55
|
+
statsd.increment "rpc.#{rpc.name}.error.application.unknown_method"
|
56
|
+
when Thrift::ApplicationException::INVALID_MESSAGE_TYPE
|
57
|
+
statsd.increment "rpc.#{rpc.name}.error.application.invalid_message_type"
|
58
|
+
when Thrift::ApplicationException::WRONG_METHOD_NAME
|
59
|
+
statsd.increment "rpc.#{rpc.name}.error.application.wrong_method_name"
|
60
|
+
when Thrift::ApplicationException::BAD_SEQUENCE_ID
|
61
|
+
statsd.increment "rpc.#{rpc.name}.error.application.bad_sequence_id"
|
62
|
+
when Thrift::ApplicationException::MISSING_RESULT
|
63
|
+
statsd.increment "rpc.#{rpc.name}.error.application.missing_result"
|
64
|
+
when Thrift::ApplicationException::INTERNAL_ERROR
|
65
|
+
statsd.increment "rpc.#{rpc.name}.error.application.internal_error"
|
66
|
+
when Thrift::ApplicationException::PROTOCOL_ERROR
|
67
|
+
statsd.increment "rpc.#{rpc.name}.error.application.protocol_error"
|
68
|
+
when Thrift::ApplicationException::INVALID_TRANSFORM
|
69
|
+
statsd.increment "rpc.#{rpc.name}.error.application.invalid_transform"
|
70
|
+
when Thrift::ApplicationException::INVALID_PROTOCOL
|
71
|
+
statsd.increment "rpc.#{rpc.name}.error.application.invalid_protocol"
|
72
|
+
when Thrift::ApplicationException::UNSUPPORTED_CLIENT_TYPE
|
73
|
+
statsd.increment "rpc.#{rpc.name}.error.application.unsupported_client_type"
|
74
|
+
end
|
75
|
+
raise ex
|
76
|
+
rescue Timeout::Error => ex
|
77
|
+
statsd.increment "rpc.#{rpc.name}.error"
|
78
|
+
statsd.increment "rpc.#{rpc.name}.error.timeout"
|
79
|
+
raise ex
|
80
|
+
rescue => ex
|
81
|
+
statsd.increment "rpc.#{rpc.name}.error"
|
82
|
+
statsd.increment "rpc.#{rpc.name}.error.other"
|
83
|
+
raise ex
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/thrifter/version.rb
CHANGED
data/test/acceptance_test.rb
CHANGED
@@ -23,6 +23,11 @@ class AcceptanceTest < MiniTest::Unit::TestCase
|
|
23
23
|
@uri = URI('tcp://localhost:9090')
|
24
24
|
end
|
25
25
|
|
26
|
+
def test_defaults_to_keep_alive
|
27
|
+
client = Thrifter.build TestClient
|
28
|
+
assert client.config.keep_alive
|
29
|
+
end
|
30
|
+
|
26
31
|
def test_defaults_to_framed_transport
|
27
32
|
client = Thrifter.build TestClient
|
28
33
|
assert_equal Thrift::FramedTransport, client.config.transport
|
@@ -40,12 +45,12 @@ class AcceptanceTest < MiniTest::Unit::TestCase
|
|
40
45
|
|
41
46
|
def test_has_reasonable_default_pool_timeout
|
42
47
|
client = Thrifter.build TestClient
|
43
|
-
assert_equal
|
48
|
+
assert_equal 2, client.config.pool_timeout
|
44
49
|
end
|
45
50
|
|
46
51
|
def test_has_reasonable_default_rpc_timeout
|
47
52
|
client = Thrifter.build TestClient
|
48
|
-
assert_equal
|
53
|
+
assert_equal 2, client.config.rpc_timeout
|
49
54
|
end
|
50
55
|
|
51
56
|
def test_defaults_to_null_statd
|
@@ -121,7 +126,7 @@ class AcceptanceTest < MiniTest::Unit::TestCase
|
|
121
126
|
client = Thrifter.build TestClient
|
122
127
|
client.config.uri = uri
|
123
128
|
|
124
|
-
socket, transport, protocol = stub, stub(open: nil, close: nil), stub
|
129
|
+
socket, transport, protocol = stub, stub(open: nil, close: nil, open?: false), stub
|
125
130
|
|
126
131
|
Thrift::Socket.expects(:new).
|
127
132
|
with(uri.host, uri.port, client.config.rpc_timeout).
|
@@ -210,10 +215,42 @@ class AcceptanceTest < MiniTest::Unit::TestCase
|
|
210
215
|
assert_equal :stubbed_response, thrifter.echo(:request)
|
211
216
|
end
|
212
217
|
|
213
|
-
def
|
214
|
-
transport = mock
|
218
|
+
def test_does_not_close_transport_when_keep_alive_set
|
219
|
+
transport = mock open?: false
|
220
|
+
client = Thrifter.build TestClient
|
221
|
+
client.config.keep_alive = true
|
222
|
+
client.config.uri = uri
|
223
|
+
client.config.transport.stubs(:new).returns(transport)
|
224
|
+
|
225
|
+
transport.expects(:open)
|
226
|
+
transport.expects(:close).never
|
227
|
+
|
228
|
+
thrifter = client.new
|
229
|
+
thrifter.echo message
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_closes_transport_if_error_occurs_when_keep_alive_set
|
233
|
+
transport = mock open?: false
|
234
|
+
client = Thrifter.build BrokenTestClient
|
235
|
+
client.config.keep_alive = true
|
236
|
+
client.config.uri = uri
|
237
|
+
client.config.transport.stubs(:new).returns(transport)
|
238
|
+
|
239
|
+
transport.expects(:open)
|
240
|
+
transport.expects(:close)
|
241
|
+
|
242
|
+
thrifter = client.new
|
243
|
+
|
244
|
+
assert_raises SimulatedError do
|
245
|
+
thrifter.echo message
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_close_the_transport_on_successful_rpc_when_no_keep_alive
|
250
|
+
transport = mock open?: false
|
215
251
|
client = Thrifter.build TestClient
|
216
252
|
client.config.uri = uri
|
253
|
+
client.config.keep_alive = false
|
217
254
|
client.config.transport.stubs(:new).returns(transport)
|
218
255
|
|
219
256
|
transport.expects(:open)
|
@@ -223,10 +260,11 @@ class AcceptanceTest < MiniTest::Unit::TestCase
|
|
223
260
|
thrifter.echo message
|
224
261
|
end
|
225
262
|
|
226
|
-
def
|
227
|
-
transport = mock
|
263
|
+
def test_close_the_transport_if_rpc_fails_when_no_keep_alive
|
264
|
+
transport = mock open?: false
|
228
265
|
client = Thrifter.build BrokenTestClient
|
229
266
|
client.config.uri = uri
|
267
|
+
client.config.keep_alive = false
|
230
268
|
client.config.transport.stubs(:new).returns(transport)
|
231
269
|
|
232
270
|
transport.expects(:open)
|
@@ -2,6 +2,7 @@ require_relative '../test_helper'
|
|
2
2
|
|
3
3
|
class RetryTest < MiniTest::Unit::TestCase
|
4
4
|
JunkError = Class.new StandardError
|
5
|
+
KnownError = Class.new StandardError
|
5
6
|
|
6
7
|
class RetryClient < Thrifter.build(TestService::Client)
|
7
8
|
include Thrifter::Retry
|
@@ -14,7 +15,7 @@ class RetryTest < MiniTest::Unit::TestCase
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def known_errors
|
17
|
-
Thrifter::Retry::
|
18
|
+
Thrifter::Retry::DEFAULT_RETRIABLE_ERRORS
|
18
19
|
end
|
19
20
|
|
20
21
|
def test_does_not_retry_on_unexpected_errors
|
@@ -43,9 +44,39 @@ class RetryTest < MiniTest::Unit::TestCase
|
|
43
44
|
assert :response == result, 'return value incorrect'
|
44
45
|
end
|
45
46
|
|
47
|
+
def test_retries_on_exceptions_specified_explicitly
|
48
|
+
thrift_client = mock
|
49
|
+
retries = sequence(:retries)
|
50
|
+
thrift_client.expects(:echo).with(:request).in_sequence(retries).raises(KnownError)
|
51
|
+
thrift_client.expects(:echo).with(:request).in_sequence(retries).returns(:response)
|
52
|
+
TestService::Client.stubs(:new).returns(thrift_client)
|
53
|
+
|
54
|
+
client = RetryClient.new
|
55
|
+
|
56
|
+
result = client.with_retry({ tries: 2, interval: 0.01, retriable: KnownError }).echo(:request)
|
57
|
+
|
58
|
+
assert :response == result, 'return value incorrect'
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_retries_on_exceptions_specified_in_array
|
62
|
+
thrift_client = mock
|
63
|
+
retries = sequence(:retries)
|
64
|
+
thrift_client.expects(:echo).with(:request).in_sequence(retries).raises(KnownError)
|
65
|
+
thrift_client.expects(:echo).with(:request).in_sequence(retries).returns(:response)
|
66
|
+
TestService::Client.stubs(:new).returns(thrift_client)
|
67
|
+
|
68
|
+
client = RetryClient.new
|
69
|
+
|
70
|
+
result = client.with_retry({ tries: 2, interval: 0.01, retriable: [ KnownError ] }).echo(:request)
|
71
|
+
|
72
|
+
assert :response == result, 'return value incorrect'
|
73
|
+
end
|
74
|
+
|
46
75
|
def test_fails_if_does_not_respond_successfully
|
76
|
+
err = known_errors.sample
|
77
|
+
|
47
78
|
thrift_client = mock
|
48
|
-
thrift_client.expects(:echo).with(:request).raises(
|
79
|
+
thrift_client.expects(:echo).with(:request).raises(err).times(5)
|
49
80
|
TestService::Client.stubs(:new).returns(thrift_client)
|
50
81
|
|
51
82
|
client = RetryClient.new
|
@@ -56,6 +87,7 @@ class RetryTest < MiniTest::Unit::TestCase
|
|
56
87
|
|
57
88
|
assert_match /5/, error.message, 'Error not descriptive'
|
58
89
|
assert_match /echo/, error.message, 'Error not descriptive'
|
90
|
+
assert_match /#{err.to_s}/, error.message, 'Missing error details'
|
59
91
|
end
|
60
92
|
|
61
93
|
def test_retries_on_application_exception
|
@@ -74,6 +106,10 @@ class RetryTest < MiniTest::Unit::TestCase
|
|
74
106
|
assert_includes known_errors, Timeout::Error
|
75
107
|
end
|
76
108
|
|
109
|
+
def test_retries_on_wrapped_client_error
|
110
|
+
assert_includes known_errors, Thrifter::ClientError
|
111
|
+
end
|
112
|
+
|
77
113
|
def test_retries_on_econrefused
|
78
114
|
assert_includes known_errors, Errno::ECONNREFUSED
|
79
115
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative '../test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class ClientMetricsTest < MiniTest::Unit::TestCase
|
4
4
|
attr_reader :rpc
|
5
5
|
|
6
6
|
def setup
|
@@ -9,14 +9,16 @@ class MetricsTest < MiniTest::Unit::TestCase
|
|
9
9
|
@rpc = Thrifter::RPC.new(:foo, :args)
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def test_happy_path_calls
|
13
13
|
app = stub
|
14
14
|
app.stubs(:call).with(rpc)
|
15
15
|
|
16
16
|
statsd = mock
|
17
|
-
statsd.expects(:time).with(rpc.
|
17
|
+
statsd.expects(:time).with('rpc.latency').yields.returns(:response)
|
18
|
+
statsd.expects(:increment).with('rpc.success')
|
19
|
+
statsd.expects(:increment).with('rpc.outgoing')
|
18
20
|
|
19
|
-
middleware = Thrifter::
|
21
|
+
middleware = Thrifter::ClientMetrics.new app, statsd
|
20
22
|
result = middleware.call rpc
|
21
23
|
|
22
24
|
assert :response == result, 'Return value incorrect'
|
@@ -28,9 +30,11 @@ class MetricsTest < MiniTest::Unit::TestCase
|
|
28
30
|
|
29
31
|
statsd = mock
|
30
32
|
statsd.expects(:time).yields
|
31
|
-
statsd.expects(:increment).with('
|
33
|
+
statsd.expects(:increment).with('rpc.outgoing')
|
34
|
+
statsd.expects(:increment).with('rpc.error.transport')
|
35
|
+
statsd.expects(:increment).with('rpc.error')
|
32
36
|
|
33
|
-
middleware = Thrifter::
|
37
|
+
middleware = Thrifter::ClientMetrics.new app, statsd
|
34
38
|
|
35
39
|
assert_raises Thrift::TransportException do
|
36
40
|
middleware.call rpc
|
@@ -43,9 +47,11 @@ class MetricsTest < MiniTest::Unit::TestCase
|
|
43
47
|
|
44
48
|
statsd = mock
|
45
49
|
statsd.expects(:time).yields
|
46
|
-
statsd.expects(:increment).with('
|
50
|
+
statsd.expects(:increment).with('rpc.outgoing')
|
51
|
+
statsd.expects(:increment).with('rpc.error.protocol')
|
52
|
+
statsd.expects(:increment).with('rpc.error')
|
47
53
|
|
48
|
-
middleware = Thrifter::
|
54
|
+
middleware = Thrifter::ClientMetrics.new app, statsd
|
49
55
|
|
50
56
|
assert_raises Thrift::ProtocolException do
|
51
57
|
middleware.call rpc
|
@@ -58,9 +64,11 @@ class MetricsTest < MiniTest::Unit::TestCase
|
|
58
64
|
|
59
65
|
statsd = mock
|
60
66
|
statsd.expects(:time).yields
|
61
|
-
statsd.expects(:increment).with('
|
67
|
+
statsd.expects(:increment).with('rpc.outgoing')
|
68
|
+
statsd.expects(:increment).with('rpc.error.application')
|
69
|
+
statsd.expects(:increment).with('rpc.error')
|
62
70
|
|
63
|
-
middleware = Thrifter::
|
71
|
+
middleware = Thrifter::ClientMetrics.new app, statsd
|
64
72
|
|
65
73
|
assert_raises Thrift::ApplicationException do
|
66
74
|
middleware.call rpc
|
@@ -73,9 +81,11 @@ class MetricsTest < MiniTest::Unit::TestCase
|
|
73
81
|
|
74
82
|
statsd = mock
|
75
83
|
statsd.expects(:time).yields
|
76
|
-
statsd.expects(:increment).with('
|
84
|
+
statsd.expects(:increment).with('rpc.outgoing')
|
85
|
+
statsd.expects(:increment).with('rpc.error.timeout')
|
86
|
+
statsd.expects(:increment).with('rpc.error')
|
77
87
|
|
78
|
-
middleware = Thrifter::
|
88
|
+
middleware = Thrifter::ClientMetrics.new app, statsd
|
79
89
|
|
80
90
|
assert_raises Timeout::Error do
|
81
91
|
middleware.call rpc
|
@@ -88,9 +98,11 @@ class MetricsTest < MiniTest::Unit::TestCase
|
|
88
98
|
|
89
99
|
statsd = mock
|
90
100
|
statsd.expects(:time).yields
|
91
|
-
statsd.expects(:increment).with('
|
101
|
+
statsd.expects(:increment).with('rpc.outgoing')
|
102
|
+
statsd.expects(:increment).with('rpc.error.other')
|
103
|
+
statsd.expects(:increment).with('rpc.error')
|
92
104
|
|
93
|
-
middleware = Thrifter::
|
105
|
+
middleware = Thrifter::ClientMetrics.new app, statsd
|
94
106
|
|
95
107
|
assert_raises StandardError do
|
96
108
|
middleware.call rpc
|
@@ -0,0 +1,497 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class RpcMetricsTest < MiniTest::Unit::TestCase
|
4
|
+
attr_reader :rpc
|
5
|
+
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
|
9
|
+
@rpc = Thrifter::RPC.new(:foo, :args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_happy_path
|
13
|
+
app = stub
|
14
|
+
app.stubs(:call).with(rpc)
|
15
|
+
|
16
|
+
statsd = mock
|
17
|
+
statsd.expects(:time).with("rpc.#{rpc.name}.latency").yields.returns(:response)
|
18
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
19
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.success")
|
20
|
+
|
21
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
22
|
+
result = middleware.call rpc
|
23
|
+
|
24
|
+
assert :response == result, 'Return value incorrect'
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_counts_unknown_transport_exceptions_and_reraises
|
28
|
+
app = stub
|
29
|
+
app.stubs(:call).with(rpc).raises(Thrift::TransportException.new(
|
30
|
+
Thrift::TransportException::UNKNOWN
|
31
|
+
))
|
32
|
+
|
33
|
+
statsd = mock
|
34
|
+
statsd.expects(:time).yields
|
35
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.transport.unknown")
|
36
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
37
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
38
|
+
|
39
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
40
|
+
|
41
|
+
assert_raises Thrift::TransportException do
|
42
|
+
middleware.call rpc
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_counts_not_open_transport_exceptions_and_reraises
|
47
|
+
app = stub
|
48
|
+
app.stubs(:call).with(rpc).raises(Thrift::TransportException.new(
|
49
|
+
Thrift::TransportException::NOT_OPEN
|
50
|
+
))
|
51
|
+
|
52
|
+
statsd = mock
|
53
|
+
statsd.expects(:time).yields
|
54
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.transport.not_open")
|
55
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
56
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
57
|
+
|
58
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
59
|
+
|
60
|
+
assert_raises Thrift::TransportException do
|
61
|
+
middleware.call rpc
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_counts_already_open_transport_exceptions_and_reraises
|
66
|
+
app = stub
|
67
|
+
app.stubs(:call).with(rpc).raises(Thrift::TransportException.new(
|
68
|
+
Thrift::TransportException::ALREADY_OPEN
|
69
|
+
))
|
70
|
+
|
71
|
+
statsd = mock
|
72
|
+
statsd.expects(:time).yields
|
73
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.transport.already_open")
|
74
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
75
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
76
|
+
|
77
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
78
|
+
|
79
|
+
assert_raises Thrift::TransportException do
|
80
|
+
middleware.call rpc
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_counts_timed_out_transport_exceptions_and_reraises
|
85
|
+
app = stub
|
86
|
+
app.stubs(:call).with(rpc).raises(Thrift::TransportException.new(
|
87
|
+
Thrift::TransportException::TIMED_OUT
|
88
|
+
))
|
89
|
+
|
90
|
+
statsd = mock
|
91
|
+
statsd.expects(:time).yields
|
92
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.transport.timeout")
|
93
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
94
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
95
|
+
|
96
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
97
|
+
|
98
|
+
assert_raises Thrift::TransportException do
|
99
|
+
middleware.call rpc
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_counts_eof_transport_exceptions_and_reraises
|
104
|
+
app = stub
|
105
|
+
app.stubs(:call).with(rpc).raises(Thrift::TransportException.new(
|
106
|
+
Thrift::TransportException::END_OF_FILE
|
107
|
+
))
|
108
|
+
|
109
|
+
statsd = mock
|
110
|
+
statsd.expects(:time).yields
|
111
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.transport.eof")
|
112
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
113
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
114
|
+
|
115
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
116
|
+
|
117
|
+
assert_raises Thrift::TransportException do
|
118
|
+
middleware.call rpc
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_counts_unknown_protocol_exceptions
|
123
|
+
app = stub
|
124
|
+
app.stubs(:call).with(rpc).raises(Thrift::ProtocolException.new(
|
125
|
+
Thrift::ProtocolException::UNKNOWN
|
126
|
+
))
|
127
|
+
|
128
|
+
statsd = mock
|
129
|
+
statsd.expects(:time).yields
|
130
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.protocol.unknown")
|
131
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
132
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
133
|
+
|
134
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
135
|
+
|
136
|
+
assert_raises Thrift::ProtocolException do
|
137
|
+
middleware.call rpc
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_counts_invalid_data_protocol_exceptions
|
142
|
+
app = stub
|
143
|
+
app.stubs(:call).with(rpc).raises(Thrift::ProtocolException.new(
|
144
|
+
Thrift::ProtocolException::INVALID_DATA
|
145
|
+
))
|
146
|
+
|
147
|
+
statsd = mock
|
148
|
+
statsd.expects(:time).yields
|
149
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.protocol.invalid_data")
|
150
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
151
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
152
|
+
|
153
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
154
|
+
|
155
|
+
assert_raises Thrift::ProtocolException do
|
156
|
+
middleware.call rpc
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_counts_negative_size_protocol_exceptions
|
161
|
+
app = stub
|
162
|
+
app.stubs(:call).with(rpc).raises(Thrift::ProtocolException.new(
|
163
|
+
Thrift::ProtocolException::NEGATIVE_SIZE
|
164
|
+
))
|
165
|
+
|
166
|
+
statsd = mock
|
167
|
+
statsd.expects(:time).yields
|
168
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.protocol.negative_size")
|
169
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
170
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
171
|
+
|
172
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
173
|
+
|
174
|
+
assert_raises Thrift::ProtocolException do
|
175
|
+
middleware.call rpc
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_counts_size_limit_protocol_exceptions
|
180
|
+
app = stub
|
181
|
+
app.stubs(:call).with(rpc).raises(Thrift::ProtocolException.new(
|
182
|
+
Thrift::ProtocolException::SIZE_LIMIT
|
183
|
+
))
|
184
|
+
|
185
|
+
statsd = mock
|
186
|
+
statsd.expects(:time).yields
|
187
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.protocol.size_limit")
|
188
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
189
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
190
|
+
|
191
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
192
|
+
|
193
|
+
assert_raises Thrift::ProtocolException do
|
194
|
+
middleware.call rpc
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_counts_bad_version_protocol_exceptions
|
199
|
+
app = stub
|
200
|
+
app.stubs(:call).with(rpc).raises(Thrift::ProtocolException.new(
|
201
|
+
Thrift::ProtocolException::BAD_VERSION
|
202
|
+
))
|
203
|
+
|
204
|
+
statsd = mock
|
205
|
+
statsd.expects(:time).yields
|
206
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.protocol.bad_version")
|
207
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
208
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
209
|
+
|
210
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
211
|
+
|
212
|
+
assert_raises Thrift::ProtocolException do
|
213
|
+
middleware.call rpc
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_counts_not_implemented_protocol_exceptions
|
218
|
+
app = stub
|
219
|
+
app.stubs(:call).with(rpc).raises(Thrift::ProtocolException.new(
|
220
|
+
Thrift::ProtocolException::NOT_IMPLEMENTED
|
221
|
+
))
|
222
|
+
|
223
|
+
statsd = mock
|
224
|
+
statsd.expects(:time).yields
|
225
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.protocol.not_implemented")
|
226
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
227
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
228
|
+
|
229
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
230
|
+
|
231
|
+
assert_raises Thrift::ProtocolException do
|
232
|
+
middleware.call rpc
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_counts_depth_limit_protocol_exceptions
|
237
|
+
app = stub
|
238
|
+
app.stubs(:call).with(rpc).raises(Thrift::ProtocolException.new(
|
239
|
+
Thrift::ProtocolException::DEPTH_LIMIT
|
240
|
+
))
|
241
|
+
|
242
|
+
statsd = mock
|
243
|
+
statsd.expects(:time).yields
|
244
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.protocol.depth_limit")
|
245
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
246
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
247
|
+
|
248
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
249
|
+
|
250
|
+
assert_raises Thrift::ProtocolException do
|
251
|
+
middleware.call rpc
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_counts_unknown_application_exceptions
|
256
|
+
app = stub
|
257
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
258
|
+
Thrift::ApplicationException::UNKNOWN
|
259
|
+
))
|
260
|
+
|
261
|
+
statsd = mock
|
262
|
+
statsd.expects(:time).yields
|
263
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.unknown")
|
264
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
265
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
266
|
+
|
267
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
268
|
+
|
269
|
+
assert_raises Thrift::ApplicationException do
|
270
|
+
middleware.call rpc
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_counts_unknown_method_application_exceptions
|
275
|
+
app = stub
|
276
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
277
|
+
Thrift::ApplicationException::UNKNOWN_METHOD
|
278
|
+
))
|
279
|
+
|
280
|
+
statsd = mock
|
281
|
+
statsd.expects(:time).yields
|
282
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.unknown_method")
|
283
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
284
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
285
|
+
|
286
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
287
|
+
|
288
|
+
assert_raises Thrift::ApplicationException do
|
289
|
+
middleware.call rpc
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def test_counts_invalid_message_type_application_exceptions
|
294
|
+
app = stub
|
295
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
296
|
+
Thrift::ApplicationException::INVALID_MESSAGE_TYPE
|
297
|
+
))
|
298
|
+
|
299
|
+
statsd = mock
|
300
|
+
statsd.expects(:time).yields
|
301
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.invalid_message_type")
|
302
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
303
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
304
|
+
|
305
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
306
|
+
|
307
|
+
assert_raises Thrift::ApplicationException do
|
308
|
+
middleware.call rpc
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_counts_wrong_method_name_application_exceptions
|
313
|
+
app = stub
|
314
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
315
|
+
Thrift::ApplicationException::WRONG_METHOD_NAME
|
316
|
+
))
|
317
|
+
|
318
|
+
statsd = mock
|
319
|
+
statsd.expects(:time).yields
|
320
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.wrong_method_name")
|
321
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
322
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
323
|
+
|
324
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
325
|
+
|
326
|
+
assert_raises Thrift::ApplicationException do
|
327
|
+
middleware.call rpc
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_counts_bad_sequence_id_application_exceptions
|
332
|
+
app = stub
|
333
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
334
|
+
Thrift::ApplicationException::BAD_SEQUENCE_ID
|
335
|
+
))
|
336
|
+
|
337
|
+
statsd = mock
|
338
|
+
statsd.expects(:time).yields
|
339
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.bad_sequence_id")
|
340
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
341
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
342
|
+
|
343
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
344
|
+
|
345
|
+
assert_raises Thrift::ApplicationException do
|
346
|
+
middleware.call rpc
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_counts_missing_result_application_exceptions
|
351
|
+
app = stub
|
352
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
353
|
+
Thrift::ApplicationException::MISSING_RESULT
|
354
|
+
))
|
355
|
+
|
356
|
+
statsd = mock
|
357
|
+
statsd.expects(:time).yields
|
358
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.missing_result")
|
359
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
360
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
361
|
+
|
362
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
363
|
+
|
364
|
+
assert_raises Thrift::ApplicationException do
|
365
|
+
middleware.call rpc
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
def test_counts_internal_error_application_exceptions
|
370
|
+
app = stub
|
371
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
372
|
+
Thrift::ApplicationException::INTERNAL_ERROR
|
373
|
+
))
|
374
|
+
|
375
|
+
statsd = mock
|
376
|
+
statsd.expects(:time).yields
|
377
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.internal_error")
|
378
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
379
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
380
|
+
|
381
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
382
|
+
|
383
|
+
assert_raises Thrift::ApplicationException do
|
384
|
+
middleware.call rpc
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_counts_protocol_error_application_exceptions
|
389
|
+
app = stub
|
390
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
391
|
+
Thrift::ApplicationException::PROTOCOL_ERROR
|
392
|
+
))
|
393
|
+
|
394
|
+
statsd = mock
|
395
|
+
statsd.expects(:time).yields
|
396
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.protocol_error")
|
397
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
398
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
399
|
+
|
400
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
401
|
+
|
402
|
+
assert_raises Thrift::ApplicationException do
|
403
|
+
middleware.call rpc
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_counts_invalid_transform_application_exceptions
|
408
|
+
app = stub
|
409
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
410
|
+
Thrift::ApplicationException::INVALID_TRANSFORM
|
411
|
+
))
|
412
|
+
|
413
|
+
statsd = mock
|
414
|
+
statsd.expects(:time).yields
|
415
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.invalid_transform")
|
416
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
417
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
418
|
+
|
419
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
420
|
+
|
421
|
+
assert_raises Thrift::ApplicationException do
|
422
|
+
middleware.call rpc
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
def test_counts_invalid_protocol_application_exceptions
|
427
|
+
app = stub
|
428
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
429
|
+
Thrift::ApplicationException::INVALID_PROTOCOL
|
430
|
+
))
|
431
|
+
|
432
|
+
statsd = mock
|
433
|
+
statsd.expects(:time).yields
|
434
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.invalid_protocol")
|
435
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
436
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
437
|
+
|
438
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
439
|
+
|
440
|
+
assert_raises Thrift::ApplicationException do
|
441
|
+
middleware.call rpc
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
def test_counts_unsupported_client_type_application_exceptions
|
446
|
+
app = stub
|
447
|
+
app.stubs(:call).with(rpc).raises(Thrift::ApplicationException.new(
|
448
|
+
Thrift::ApplicationException::UNSUPPORTED_CLIENT_TYPE
|
449
|
+
))
|
450
|
+
|
451
|
+
statsd = mock
|
452
|
+
statsd.expects(:time).yields
|
453
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.application.unsupported_client_type")
|
454
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
455
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
456
|
+
|
457
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
458
|
+
|
459
|
+
assert_raises Thrift::ApplicationException do
|
460
|
+
middleware.call rpc
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
def test_counts_timeouts
|
465
|
+
app = stub
|
466
|
+
app.stubs(:call).with(rpc).raises(Timeout::Error)
|
467
|
+
|
468
|
+
statsd = mock
|
469
|
+
statsd.expects(:time).yields
|
470
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.timeout")
|
471
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.outgoing")
|
472
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error")
|
473
|
+
|
474
|
+
middleware = Thrifter::RpcMetrics.new app, statsd
|
475
|
+
|
476
|
+
assert_raises Timeout::Error do
|
477
|
+
middleware.call rpc
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_counts_other_errors
|
482
|
+
app = stub
|
483
|
+
app.stubs(:call).with(rpc).raises(StandardError)
|
484
|
+
|
485
|
+
statsd = mock
|
486
|
+
statsd.expects(:time).yields
|
487
|
+
statsd.expects(:increment).with("rpc.#{rpc.name}.error.other")
|
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 StandardError do
|
494
|
+
middleware.call rpc
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
data/test/test_helper.rb
CHANGED
data/thrifter.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "thrifter"
|
8
8
|
spec.version = Thrifter::VERSION
|
9
9
|
spec.authors = ["ahawkins"]
|
10
|
-
spec.email = ["
|
10
|
+
spec.email = ["hi@ahawkins.me"]
|
11
11
|
spec.summary = %q{Production ready Thrift client with improved semantics}
|
12
12
|
spec.description = %q{}
|
13
13
|
spec.homepage = "https://github.com/saltside/thrifter"
|
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency "bundler", "~> 1.7"
|
31
31
|
spec.add_development_dependency "rake", "~> 10.0"
|
32
32
|
spec.add_development_dependency "mocha"
|
33
|
-
spec.add_development_dependency "sidekiq"
|
33
|
+
spec.add_development_dependency "sidekiq", "~> 4.2"
|
34
34
|
spec.add_development_dependency "sidekiq-thrift_arguments"
|
35
35
|
spec.add_development_dependency "eventmachine"
|
36
36
|
end
|
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: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ahawkins
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thrift
|
@@ -168,16 +168,16 @@ dependencies:
|
|
168
168
|
name: sidekiq
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
|
-
- - "
|
171
|
+
- - "~>"
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: '
|
173
|
+
version: '4.2'
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
|
-
- - "
|
178
|
+
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version: '
|
180
|
+
version: '4.2'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: sidekiq-thrift_arguments
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -208,7 +208,7 @@ dependencies:
|
|
208
208
|
version: '0'
|
209
209
|
description: ''
|
210
210
|
email:
|
211
|
-
-
|
211
|
+
- hi@ahawkins.me
|
212
212
|
executables: []
|
213
213
|
extensions: []
|
214
214
|
extra_rdoc_files: []
|
@@ -227,8 +227,9 @@ 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/middleware/client_metrics.rb
|
230
231
|
- lib/thrifter/middleware/error_wrapping.rb
|
231
|
-
- lib/thrifter/middleware/
|
232
|
+
- lib/thrifter/middleware/rpc_metrics.rb
|
232
233
|
- lib/thrifter/middleware/validation.rb
|
233
234
|
- lib/thrifter/version.rb
|
234
235
|
- script/monkey-client
|
@@ -238,8 +239,9 @@ files:
|
|
238
239
|
- test/extensions/ping_test.rb
|
239
240
|
- test/extensions/queueing_test.rb
|
240
241
|
- test/extensions/retry_test.rb
|
242
|
+
- test/middleware/client_metrics_test.rb
|
241
243
|
- test/middleware/error_wrapping_test.rb
|
242
|
-
- test/middleware/
|
244
|
+
- test/middleware/rpc_metrics_test.rb
|
243
245
|
- test/middleware/validation_test.rb
|
244
246
|
- test/test_helper.rb
|
245
247
|
- thrifter.gemspec
|
@@ -266,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
266
268
|
version: '0'
|
267
269
|
requirements: []
|
268
270
|
rubyforge_project:
|
269
|
-
rubygems_version: 2.
|
271
|
+
rubygems_version: 2.5.1
|
270
272
|
signing_key:
|
271
273
|
specification_version: 4
|
272
274
|
summary: Production ready Thrift client with improved semantics
|
@@ -275,7 +277,8 @@ test_files:
|
|
275
277
|
- test/extensions/ping_test.rb
|
276
278
|
- test/extensions/queueing_test.rb
|
277
279
|
- test/extensions/retry_test.rb
|
280
|
+
- test/middleware/client_metrics_test.rb
|
278
281
|
- test/middleware/error_wrapping_test.rb
|
279
|
-
- test/middleware/
|
282
|
+
- test/middleware/rpc_metrics_test.rb
|
280
283
|
- test/middleware/validation_test.rb
|
281
284
|
- test/test_helper.rb
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module Thrifter
|
2
|
-
class Metrics
|
3
|
-
include Concord.new(:app, :statsd)
|
4
|
-
|
5
|
-
def call(rpc)
|
6
|
-
statsd.time rpc.name do
|
7
|
-
app.call rpc
|
8
|
-
end
|
9
|
-
rescue Thrift::TransportException => ex
|
10
|
-
statsd.increment 'errors.transport'
|
11
|
-
raise ex
|
12
|
-
rescue Thrift::ProtocolException => ex
|
13
|
-
statsd.increment 'errors.protocol'
|
14
|
-
raise ex
|
15
|
-
rescue Thrift::ApplicationException => ex
|
16
|
-
statsd.increment 'errors.application'
|
17
|
-
raise ex
|
18
|
-
rescue Timeout::Error => ex
|
19
|
-
statsd.increment 'errors.timeout'
|
20
|
-
raise ex
|
21
|
-
rescue => ex
|
22
|
-
statsd.increment 'errors.other'
|
23
|
-
raise ex
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|