thrifter 0.1.3 → 1.0.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/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
|