thrift_client 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +9 -1
- data/Manifest +13 -1
- data/{README → README.rdoc} +9 -1
- data/Rakefile +0 -1
- data/lib/thrift_client/connection/base.rb +20 -0
- data/lib/thrift_client/connection/factory.rb +11 -0
- data/lib/thrift_client/connection/http.rb +18 -0
- data/lib/thrift_client/connection/socket.rb +22 -0
- data/lib/thrift_client/connection.rb +5 -0
- data/lib/thrift_client/event_machine.rb +141 -0
- data/lib/thrift_client/simple.rb +263 -0
- data/lib/thrift_client/thrift.rb +0 -1
- data/lib/thrift_client.rb +31 -47
- data/test/greeter/greeter.rb +77 -0
- data/test/greeter/greeter.thrift +3 -0
- data/test/greeter/server.rb +40 -0
- data/test/simple_test.rb +5 -5
- data/test/test_helper.rb +5 -1
- data/test/thrift_client_http_test.rb +54 -0
- data/test/thrift_client_test.rb +47 -34
- data/thrift_client.gemspec +8 -6
- data.tar.gz.sig +0 -0
- metadata +47 -6
- metadata.gz.sig +3 -0
data/CHANGELOG
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
v0.
|
1
|
+
v0.4.0. Add new EventMachine transport. This requires two layers of transport
|
2
|
+
configurability:
|
3
|
+
options[:transport] for EventMachine or Socket transports
|
4
|
+
options[:transport_wrapper] for optional Buffered or Framed Transport.
|
5
|
+
Clients will need to update their options to ensure they don't conflict with this change. (mperham)
|
6
|
+
Revert global timeouts. (ryanking)
|
7
|
+
Add support for HTTPClientTransport (Chris Sepic)
|
8
|
+
|
9
|
+
v0.3.3. Allow for a timeout over all requests in a call.
|
2
10
|
|
3
11
|
v0.3.2. Fix connection close bug (nkallen, mattknox).
|
4
12
|
|
data/Manifest
CHANGED
@@ -1,9 +1,21 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
LICENSE
|
3
3
|
Manifest
|
4
|
-
README
|
4
|
+
README.rdoc
|
5
5
|
Rakefile
|
6
6
|
lib/thrift_client.rb
|
7
|
+
lib/thrift_client/connection.rb
|
8
|
+
lib/thrift_client/connection/base.rb
|
9
|
+
lib/thrift_client/connection/factory.rb
|
10
|
+
lib/thrift_client/connection/http.rb
|
11
|
+
lib/thrift_client/connection/socket.rb
|
12
|
+
lib/thrift_client/event_machine.rb
|
13
|
+
lib/thrift_client/simple.rb
|
7
14
|
lib/thrift_client/thrift.rb
|
15
|
+
test/greeter/greeter.rb
|
16
|
+
test/greeter/greeter.thrift
|
17
|
+
test/greeter/server.rb
|
18
|
+
test/simple_test.rb
|
8
19
|
test/test_helper.rb
|
20
|
+
test/thrift_client_http_test.rb
|
9
21
|
test/thrift_client_test.rb
|
data/{README → README.rdoc}
RENAMED
@@ -27,7 +27,7 @@ Instantiate a client:
|
|
27
27
|
You can then make calls to the server via the <tt>client</tt> instance as if was your internal Thrift client. The connection will be opened lazily and methods will be proxied through.
|
28
28
|
|
29
29
|
client.get_string_list_property("keyspaces")
|
30
|
-
|
30
|
+
|
31
31
|
On failures, the client will try the remaining servers in the list before giving up. See ThriftClient for more.
|
32
32
|
|
33
33
|
== Installation
|
@@ -36,6 +36,14 @@ You need Ruby 1.8 or 1.9. If you have those, just run:
|
|
36
36
|
|
37
37
|
sudo gem install thrift_client
|
38
38
|
|
39
|
+
== Contributing
|
40
|
+
|
41
|
+
To contribute changes:
|
42
|
+
|
43
|
+
1. Fork the project
|
44
|
+
2. make your change, adding tests
|
45
|
+
3. send a pull request to fauna and ryanking
|
46
|
+
|
39
47
|
== Reporting problems
|
40
48
|
|
41
49
|
The Github issue tracker is {here}[http://github.com/fauna/thrift_client/issues].
|
data/Rakefile
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Connection
|
2
|
+
class Base
|
3
|
+
attr_accessor :transport, :server
|
4
|
+
|
5
|
+
def initialize(transport, transport_wrapper, server, timeout, error_hash)
|
6
|
+
@transport = transport
|
7
|
+
@transport_wrapper = transport_wrapper
|
8
|
+
@server = server
|
9
|
+
@timeout = timeout
|
10
|
+
@error_type = error_hash[:handles_error]
|
11
|
+
end
|
12
|
+
|
13
|
+
def connect!
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
def close
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Connection
|
2
|
+
class Factory
|
3
|
+
def self.create(transport, transport_wrapper, server, timeout)
|
4
|
+
if transport == Thrift::HTTPClientTransport
|
5
|
+
Connection::HTTP.new(transport, transport_wrapper, server, timeout, :handles_error => Errno::ECONNREFUSED)
|
6
|
+
else
|
7
|
+
Connection::Socket.new(transport, transport_wrapper, server, timeout, :handles_error => Thrift::TransportException)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Connection
|
2
|
+
class HTTP < Base
|
3
|
+
def connect!
|
4
|
+
uri = parse_server(@server)
|
5
|
+
@transport = Thrift::HTTPClientTransport.new(@server)
|
6
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
7
|
+
http.use_ssl = uri.scheme == "https"
|
8
|
+
http.get(uri.path)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def parse_server(server)
|
13
|
+
uri = URI.parse(server)
|
14
|
+
raise ArgumentError, 'Servers must start with http' unless uri.scheme =~ /^http/
|
15
|
+
uri
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Connection
|
2
|
+
class Socket < Base
|
3
|
+
def close
|
4
|
+
@transport.close
|
5
|
+
end
|
6
|
+
|
7
|
+
def connect!
|
8
|
+
host, port = parse_server(@server)
|
9
|
+
@transport = @transport.new(*[host, port.to_i, @timeout])
|
10
|
+
@transport = @transport_wrapper.new(@transport) if @transport_wrapper
|
11
|
+
@transport.open
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def parse_server(server)
|
17
|
+
host, port = server.to_s.split(":")
|
18
|
+
raise ArgumentError, 'Servers must be in the form "host:port"' unless host and port
|
19
|
+
[host, port]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
raise RuntimeError, "The eventmachine transport requires Ruby 1.9.x" if RUBY_VERSION < '1.9.0'
|
2
|
+
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'fiber'
|
5
|
+
|
6
|
+
# EventMachine-ready Thrift connection
|
7
|
+
# Should not be used with a transport wrapper since it already performs buffering in Ruby.
|
8
|
+
module Thrift
|
9
|
+
class EventMachineTransport < BaseTransport
|
10
|
+
def initialize(host, port=9090, timeout=5)
|
11
|
+
@host, @port, @timeout = host, port, timeout
|
12
|
+
@connection = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def open?
|
16
|
+
@connection && @connection.connected?
|
17
|
+
end
|
18
|
+
|
19
|
+
def open
|
20
|
+
@connection = EventMachineConnection.connect(@host, @port, @timeout)
|
21
|
+
end
|
22
|
+
|
23
|
+
def close
|
24
|
+
@connection.close
|
25
|
+
end
|
26
|
+
|
27
|
+
def read(sz)
|
28
|
+
@connection.blocking_read(sz)
|
29
|
+
end
|
30
|
+
|
31
|
+
def write(buf)
|
32
|
+
@connection.send_data(buf)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module EventMachineConnection
|
37
|
+
GARBAGE_BUFFER_SIZE = 4096 # 4kB
|
38
|
+
|
39
|
+
include EM::Deferrable
|
40
|
+
|
41
|
+
def self.connect(host='localhost', port=9090, timeout=5, &block)
|
42
|
+
EM.connect(host, port, self, host, port) do |conn|
|
43
|
+
conn.pending_connect_timeout = timeout
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def trap
|
48
|
+
begin
|
49
|
+
yield
|
50
|
+
rescue Exception => ex
|
51
|
+
puts ex.message
|
52
|
+
puts ex.backtrace.join("\n")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(host, port=9090)
|
57
|
+
@host, @port = host, port
|
58
|
+
@index = 0
|
59
|
+
@reconnecting = false
|
60
|
+
@connected = false
|
61
|
+
@buf = ''
|
62
|
+
end
|
63
|
+
|
64
|
+
def close
|
65
|
+
trap do
|
66
|
+
@connected = false
|
67
|
+
close_connection(true)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def blocking_read(size)
|
72
|
+
trap do
|
73
|
+
if can_read?(size)
|
74
|
+
yank(size)
|
75
|
+
else
|
76
|
+
raise ArgumentError, "Unexpected state" if @size or @callback
|
77
|
+
|
78
|
+
fiber = Fiber.current
|
79
|
+
@size = size
|
80
|
+
@callback = proc { |data|
|
81
|
+
fiber.resume(data)
|
82
|
+
}
|
83
|
+
Fiber.yield
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def receive_data(data)
|
89
|
+
trap do
|
90
|
+
(@buf) << data
|
91
|
+
|
92
|
+
if @callback and can_read?(@size)
|
93
|
+
callback = @callback
|
94
|
+
data = yank(@size)
|
95
|
+
@callback = @size = nil
|
96
|
+
callback.call(data)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def connected?
|
102
|
+
@connected
|
103
|
+
end
|
104
|
+
|
105
|
+
def connection_completed
|
106
|
+
@reconnecting = false
|
107
|
+
@connected = true
|
108
|
+
succeed
|
109
|
+
end
|
110
|
+
|
111
|
+
def unbind
|
112
|
+
# If we disconnect, try to reconnect
|
113
|
+
if @connected or !@reconnecting
|
114
|
+
EM.add_timer(1) {
|
115
|
+
# XXX Connect timeout?
|
116
|
+
reconnect @host, @port
|
117
|
+
}
|
118
|
+
@connected = false
|
119
|
+
@reconnecting = true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def can_read?(size)
|
124
|
+
@buf.size >= @index + size
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def yank(len)
|
130
|
+
data = @buf.slice(@index, len)
|
131
|
+
@index += len
|
132
|
+
@index = @buf.size if @index > @buf.size
|
133
|
+
if @index >= GARBAGE_BUFFER_SIZE
|
134
|
+
@buf = @buf.slice(@index..-1)
|
135
|
+
@index = 0
|
136
|
+
end
|
137
|
+
data
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'getoptlong'
|
3
|
+
|
4
|
+
class ThriftClient
|
5
|
+
|
6
|
+
# This is a simplified form of thrift, useful for clients only, and not
|
7
|
+
# making any attempt to have good performance. It's intended to be used by
|
8
|
+
# small command-line tools that don't want to install a dozen ruby files.
|
9
|
+
module Simple
|
10
|
+
VERSION_1 = 0x8001
|
11
|
+
|
12
|
+
# message types
|
13
|
+
CALL, REPLY, EXCEPTION = (1..3).to_a
|
14
|
+
|
15
|
+
# value types
|
16
|
+
STOP, VOID, BOOL, BYTE, DOUBLE, _, I16, _, I32, _, I64, STRING, STRUCT, MAP, SET, LIST = (0..15).to_a
|
17
|
+
|
18
|
+
FORMATS = {
|
19
|
+
BYTE => "c",
|
20
|
+
DOUBLE => "G",
|
21
|
+
I16 => "n",
|
22
|
+
I32 => "N",
|
23
|
+
}
|
24
|
+
|
25
|
+
SIZES = {
|
26
|
+
BYTE => 1,
|
27
|
+
DOUBLE => 8,
|
28
|
+
I16 => 2,
|
29
|
+
I32 => 4,
|
30
|
+
}
|
31
|
+
|
32
|
+
module ComplexType
|
33
|
+
module Extends
|
34
|
+
def type_id=(n)
|
35
|
+
@type_id = n
|
36
|
+
end
|
37
|
+
|
38
|
+
def type_id
|
39
|
+
@type_id
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Includes
|
44
|
+
def to_i
|
45
|
+
self.class.type_id
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
args = self.values.map { |v| self.class.type_id == STRUCT ? v.name : v.to_s }.join(", ")
|
50
|
+
"#{self.class.name}.new(#{args})"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.make_type(type_id, name, *args)
|
56
|
+
klass = Struct.new("STT_#{name}", *args)
|
57
|
+
klass.send(:extend, ComplexType::Extends)
|
58
|
+
klass.send(:include, ComplexType::Includes)
|
59
|
+
klass.type_id = type_id
|
60
|
+
klass
|
61
|
+
end
|
62
|
+
|
63
|
+
ListType = make_type(LIST, "ListType", :element_type)
|
64
|
+
MapType = make_type(MAP, "MapType", :key_type, :value_type)
|
65
|
+
SetType = make_type(SET, "SetType", :element_type)
|
66
|
+
StructType = make_type(STRUCT, "StructType", :struct_class)
|
67
|
+
|
68
|
+
class << self
|
69
|
+
def pack_value(type, value)
|
70
|
+
case type
|
71
|
+
when BOOL
|
72
|
+
[ value ? 1 : 0 ].pack("c")
|
73
|
+
when STRING
|
74
|
+
[ value.size, value ].pack("Na*")
|
75
|
+
when I64
|
76
|
+
[ value >> 32, value & 0xffffffff ].pack("NN")
|
77
|
+
when ListType
|
78
|
+
[ type.element_type.to_i, value.size ].pack("cN") + value.map { |item| pack_value(type.element_type, item) }.join("")
|
79
|
+
when MapType
|
80
|
+
[ type.key_type.to_i, type.value_type.to_i, value.size ].pack("ccN") + value.map { |k, v| pack_value(type.key_type, k) + pack_value(type.value_type, v) }.join("")
|
81
|
+
when SetType
|
82
|
+
[ type.element_type.to_i, value.size ].pack("cN") + value.map { |item| pack_value(type.element_type, item) }.join("")
|
83
|
+
when StructType
|
84
|
+
value._pack
|
85
|
+
else
|
86
|
+
[ value ].pack(FORMATS[type])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def pack_request(method_name, arg_struct, request_id=0)
|
91
|
+
[ VERSION_1, CALL, method_name.to_s.size, method_name.to_s, request_id, arg_struct._pack ].pack("nnNa*Na*")
|
92
|
+
end
|
93
|
+
|
94
|
+
def read_value(s, type)
|
95
|
+
case type
|
96
|
+
when BOOL
|
97
|
+
s.read(1).unpack("c").first != 0
|
98
|
+
when STRING
|
99
|
+
len = s.read(4).unpack("N").first
|
100
|
+
s.read(len)
|
101
|
+
when I64
|
102
|
+
hi, lo = s.read(8).unpack("NN")
|
103
|
+
(hi << 32) | lo
|
104
|
+
when LIST
|
105
|
+
read_list(s)
|
106
|
+
when MAP
|
107
|
+
read_map(s)
|
108
|
+
when STRUCT
|
109
|
+
read_struct(s)
|
110
|
+
when ListType
|
111
|
+
read_list(s, type.element_type)
|
112
|
+
when MapType
|
113
|
+
read_map(s, type.key_type, type.value_type)
|
114
|
+
when StructType
|
115
|
+
read_struct(s, type.struct_class)
|
116
|
+
else
|
117
|
+
s.read(SIZES[type]).unpack(FORMATS[type]).first
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def read_list(s, element_type=nil)
|
122
|
+
etype, len = s.read(5).unpack("cN")
|
123
|
+
expected_type = (element_type and element_type.to_i == etype.to_i) ? element_type : etype
|
124
|
+
rv = []
|
125
|
+
len.times do
|
126
|
+
rv << read_value(s, expected_type)
|
127
|
+
end
|
128
|
+
rv
|
129
|
+
end
|
130
|
+
|
131
|
+
def read_map(s, key_type=nil, value_type=nil)
|
132
|
+
ktype, vtype, len = s.read(6).unpack("ccN")
|
133
|
+
rv = {}
|
134
|
+
expected_key_type, expected_value_type = if key_type and value_type and key_type.to_i == ktype and value_type.to_i == vtype
|
135
|
+
[ key_type, value_type ]
|
136
|
+
else
|
137
|
+
[ ktype, vtype ]
|
138
|
+
end
|
139
|
+
len.times do
|
140
|
+
key = read_value(s, expected_key_type)
|
141
|
+
value = read_value(s, expected_value_type)
|
142
|
+
rv[key] = value
|
143
|
+
end
|
144
|
+
rv
|
145
|
+
end
|
146
|
+
|
147
|
+
def read_struct(s, struct_class=nil)
|
148
|
+
rv = struct_class.new()
|
149
|
+
while true
|
150
|
+
type = s.read(1).unpack("c").first
|
151
|
+
return rv if type == STOP
|
152
|
+
fid = s.read(2).unpack("n").first
|
153
|
+
field = struct_class ? struct_class._fields.find { |f| (f.fid == fid) and (f.type.to_i == type) } : nil
|
154
|
+
value = read_value(s, field ? field.type : type)
|
155
|
+
rv[field.name] = value if field
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def read_response(s, rv_class)
|
160
|
+
version, message_type, method_name_len = s.read(8).unpack("nnN")
|
161
|
+
method_name = s.read(method_name_len)
|
162
|
+
seq_id = s.read(4).unpack("N").first
|
163
|
+
[ method_name, seq_id, read_struct(s, rv_class).rv ]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
## ----------------------------------------
|
168
|
+
|
169
|
+
class Field
|
170
|
+
attr_accessor :name, :type, :fid
|
171
|
+
|
172
|
+
def initialize(name, type, fid)
|
173
|
+
@name = name
|
174
|
+
@type = type
|
175
|
+
@fid = fid
|
176
|
+
end
|
177
|
+
|
178
|
+
def pack(value)
|
179
|
+
value.nil? ? "" : [ type.to_i, fid, ThriftClient::Simple.pack_value(type, value) ].pack("cna*")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class ThriftException < RuntimeError
|
184
|
+
def initialize(reason)
|
185
|
+
@reason = reason
|
186
|
+
end
|
187
|
+
|
188
|
+
def to_s
|
189
|
+
"ThriftException(#{@reason.inspect})"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
module ThriftStruct
|
194
|
+
module Include
|
195
|
+
def _pack
|
196
|
+
self.class._fields.map { |f| f.pack(self[f.name]) }.join + [ STOP ].pack("c")
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
module Extend
|
201
|
+
def _fields
|
202
|
+
@fields
|
203
|
+
end
|
204
|
+
|
205
|
+
def _fields=(f)
|
206
|
+
@fields = f
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.make_struct(name, *fields)
|
212
|
+
st_name = "ST_#{name}"
|
213
|
+
if Struct.constants.include?(st_name)
|
214
|
+
warn "#{caller[0]}: Struct::#{st_name} is already defined; returning original class."
|
215
|
+
Struct.const_get(st_name)
|
216
|
+
else
|
217
|
+
names = fields.map { |f| f.name.to_sym }
|
218
|
+
klass = Struct.new(st_name, *names)
|
219
|
+
klass.send(:include, ThriftStruct::Include)
|
220
|
+
klass.send(:extend, ThriftStruct::Extend)
|
221
|
+
klass._fields = fields
|
222
|
+
klass
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
class ThriftService
|
227
|
+
def initialize(sock)
|
228
|
+
@sock = sock
|
229
|
+
end
|
230
|
+
|
231
|
+
def self._arg_structs
|
232
|
+
@_arg_structs = {} if @_arg_structs.nil?
|
233
|
+
@_arg_structs
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.thrift_method(name, rtype, *args)
|
237
|
+
arg_struct = ThriftClient::Simple.make_struct("Args__#{self.name}__#{name}", *args)
|
238
|
+
rv_struct = ThriftClient::Simple.make_struct("Retval__#{self.name}__#{name}", ThriftClient::Simple::Field.new(:rv, rtype, 0))
|
239
|
+
_arg_structs[name.to_sym] = [ arg_struct, rv_struct ]
|
240
|
+
|
241
|
+
arg_names = args.map { |a| a.name.to_s }.join(", ")
|
242
|
+
class_eval "def #{name}(#{arg_names}); _proxy(:#{name}#{args.size > 0 ? ', ' : ''}#{arg_names}); end"
|
243
|
+
end
|
244
|
+
|
245
|
+
def _proxy(method_name, *args)
|
246
|
+
cls = self.class.ancestors.find { |cls| cls.respond_to?(:_arg_structs) and cls._arg_structs[method_name.to_sym] }
|
247
|
+
arg_class, rv_class = cls._arg_structs[method_name.to_sym]
|
248
|
+
arg_struct = arg_class.new(*args)
|
249
|
+
@sock.write(ThriftClient::Simple.pack_request(method_name, arg_struct))
|
250
|
+
rv = ThriftClient::Simple.read_response(@sock, rv_class)
|
251
|
+
rv[2]
|
252
|
+
end
|
253
|
+
|
254
|
+
# convenience. robey is lazy.
|
255
|
+
[[ :field, "Field.new" ], [ :struct, "StructType.new" ],
|
256
|
+
[ :list, "ListType.new" ], [ :map, "MapType.new" ]].each do |new_name, old_name|
|
257
|
+
class_eval "def self.#{new_name}(*args); ThriftClient::Simple::#{old_name}(*args); end"
|
258
|
+
end
|
259
|
+
|
260
|
+
[ :void, :bool, :byte, :double, :i16, :i32, :i64, :string ].each { |sym| class_eval "def self.#{sym}; ThriftClient::Simple::#{sym.to_s.upcase}; end" }
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
data/lib/thrift_client/thrift.rb
CHANGED
data/lib/thrift_client.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
if ENV["ANCIENT_THRIFT"]
|
3
2
|
$LOAD_PATH.unshift("/Users/eweaver/p/twitter/rails/vendor/gems/thrift-751142/lib")
|
4
3
|
$LOAD_PATH.unshift("/Users/eweaver/p/twitter/rails/vendor/gems/thrift-751142/ext")
|
@@ -8,18 +7,19 @@ else
|
|
8
7
|
require 'thrift'
|
9
8
|
end
|
10
9
|
|
11
|
-
require 'timeout'
|
12
10
|
require 'rubygems'
|
13
11
|
require 'thrift_client/thrift'
|
12
|
+
require 'thrift_client/connection'
|
14
13
|
|
15
14
|
class ThriftClient
|
15
|
+
|
16
16
|
class NoServersAvailable < StandardError; end
|
17
|
-
class GlobalThriftClientTimeout < Timeout::Error; end
|
18
17
|
|
19
18
|
DEFAULTS = {
|
20
19
|
:protocol => Thrift::BinaryProtocol,
|
21
20
|
:protocol_extra_params => [],
|
22
|
-
:transport => Thrift::
|
21
|
+
:transport => Thrift::Socket,
|
22
|
+
:transport_wrapper => Thrift::FramedTransport,
|
23
23
|
:randomize_server_list => true,
|
24
24
|
:exception_classes => [
|
25
25
|
IOError,
|
@@ -52,8 +52,7 @@ Valid optional parameters are:
|
|
52
52
|
<tt>:retries</tt>:: How many times to retry a request. Defaults to the number of servers defined.
|
53
53
|
<tt>:server_retry_period</tt>:: How many seconds to wait before trying to reconnect after marking all servers as down. Defaults to <tt>1</tt>. Set to <tt>nil</tt> to retry endlessly.
|
54
54
|
<tt>:server_max_requests</tt>:: How many requests to perform before moving on to the next server in the pool, regardless of error status. Defaults to <tt>nil</tt> (no limit).
|
55
|
-
<tt>:
|
56
|
-
<tt>:timeout</tt>:: Specify the default timeout in seconds per connection. Defaults to <tt>1</tt>.
|
55
|
+
<tt>:timeout</tt>:: Specify the default timeout in seconds. Defaults to <tt>1</tt>.
|
57
56
|
<tt>:timeout_overrides</tt>:: Specify additional timeouts on a per-method basis, in seconds. Only works with <tt>Thrift::BufferedTransport</tt>.
|
58
57
|
<tt>:defaults</tt>:: Specify default values to return on a per-method basis, if <tt>:raise</tt> is set to false.
|
59
58
|
|
@@ -66,17 +65,16 @@ Valid optional parameters are:
|
|
66
65
|
@retries = options[:retries] || @server_list.size
|
67
66
|
|
68
67
|
if @options[:timeout_overrides].any?
|
69
|
-
if @options[:transport].
|
68
|
+
if (@options[:transport_wrapper] || @options[:transport]).method_defined?(:timeout=)
|
70
69
|
@set_timeout = true
|
71
70
|
else
|
72
|
-
warn "ThriftClient: Timeout overrides have no effect with with transport type #{@options[:transport]}"
|
71
|
+
warn "ThriftClient: Timeout overrides have no effect with with transport type #{(@options[:transport_wrapper] || @options[:transport])}"
|
73
72
|
end
|
74
73
|
end
|
75
74
|
|
76
75
|
@request_count = 0
|
77
76
|
@max_requests = @options[:server_max_requests]
|
78
77
|
@retry_period = @options[:server_retry_period]
|
79
|
-
@global_timeout = @options[:global_timeout] || 0
|
80
78
|
rebuild_live_server_list!
|
81
79
|
|
82
80
|
@client_class.instance_methods.each do |method_name|
|
@@ -88,23 +86,18 @@ Valid optional parameters are:
|
|
88
86
|
|
89
87
|
# Force the client to connect to the server.
|
90
88
|
def connect!
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
Thrift::Socket.new(host, port.to_i, @options[:timeout]))
|
97
|
-
@transport.open
|
98
|
-
@current_server = server
|
99
|
-
@client = @client_class.new(@options[:protocol].new(@transport, *@options[:protocol_extra_params]))
|
100
|
-
rescue Thrift::TransportException
|
89
|
+
@current_server = next_server
|
90
|
+
@connection = Connection::Factory.create(@options[:transport], @options[:transport_wrapper], @current_server, @options[:timeout])
|
91
|
+
@connection.connect!
|
92
|
+
@client = @client_class.new(@options[:protocol].new(@connection.transport, *@options[:protocol_extra_params]))
|
93
|
+
rescue Thrift::TransportException, Errno::ECONNREFUSED
|
101
94
|
@transport.close rescue nil
|
102
95
|
retry
|
103
96
|
end
|
104
97
|
|
105
98
|
# Force the client to disconnect from the server.
|
106
99
|
def disconnect!(keep = true)
|
107
|
-
@
|
100
|
+
@connection.close rescue nil
|
108
101
|
|
109
102
|
# Keep live servers in the list if we have a retry period. Otherwise,
|
110
103
|
# always eject, because we will always re-add them.
|
@@ -119,16 +112,26 @@ Valid optional parameters are:
|
|
119
112
|
|
120
113
|
private
|
121
114
|
|
122
|
-
def
|
123
|
-
|
124
|
-
|
115
|
+
def next_server
|
116
|
+
if @retry_period
|
117
|
+
rebuild_live_server_list! if Time.now > @last_rebuild + @retry_period
|
118
|
+
raise NoServersAvailable, "No live servers in #{@server_list.inspect} since #{@last_rebuild.inspect}." if @live_server_list.empty?
|
119
|
+
elsif @live_server_list.empty?
|
120
|
+
rebuild_live_server_list!
|
121
|
+
end
|
122
|
+
@live_server_list.pop
|
123
|
+
end
|
124
|
+
|
125
|
+
def rebuild_live_server_list!
|
126
|
+
@last_rebuild = Time.now
|
127
|
+
if @options[:randomize_server_list]
|
128
|
+
@live_server_list = @server_list.sort_by { rand }
|
129
|
+
else
|
130
|
+
@live_server_list = @server_list.dup
|
125
131
|
end
|
126
|
-
rescue GlobalThriftClientTimeout => e
|
127
|
-
disconnect!(false)
|
128
|
-
raise e
|
129
132
|
end
|
130
133
|
|
131
|
-
def
|
134
|
+
def proxy(method_name, *args)
|
132
135
|
disconnect! if @max_requests and @request_count >= @max_requests
|
133
136
|
connect! unless @client
|
134
137
|
|
@@ -148,27 +151,8 @@ Valid optional parameters are:
|
|
148
151
|
@client.timeout = @options[:timeout_overrides][method_name.to_sym] || @options[:timeout]
|
149
152
|
end
|
150
153
|
|
151
|
-
def handle_exception(e, method_name, args)
|
154
|
+
def handle_exception(e, method_name, args=nil)
|
152
155
|
raise e if @options[:raise]
|
153
156
|
@options[:defaults][method_name.to_sym]
|
154
157
|
end
|
155
|
-
|
156
|
-
def next_server
|
157
|
-
if @retry_period
|
158
|
-
rebuild_live_server_list! if Time.now > @last_rebuild + @retry_period
|
159
|
-
raise NoServersAvailable, "No live servers in #{@server_list.inspect} since #{@last_rebuild.inspect}." if @live_server_list.empty?
|
160
|
-
elsif @live_server_list.empty?
|
161
|
-
rebuild_live_server_list!
|
162
|
-
end
|
163
|
-
@live_server_list.pop
|
164
|
-
end
|
165
|
-
|
166
|
-
def rebuild_live_server_list!
|
167
|
-
@last_rebuild = Time.now
|
168
|
-
if @options[:randomize_server_list]
|
169
|
-
@live_server_list = @server_list.sort_by { rand }
|
170
|
-
else
|
171
|
-
@live_server_list = @server_list.dup
|
172
|
-
end
|
173
|
-
end
|
174
158
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#
|
2
|
+
# Autogenerated by Thrift
|
3
|
+
#
|
4
|
+
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'thrift'
|
8
|
+
|
9
|
+
module Greeter
|
10
|
+
class Client
|
11
|
+
include ::Thrift::Client
|
12
|
+
|
13
|
+
def greeting(name)
|
14
|
+
send_greeting(name)
|
15
|
+
return recv_greeting()
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_greeting(name)
|
19
|
+
send_message('greeting', Greeting_args, :name => name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def recv_greeting()
|
23
|
+
result = receive_message(Greeting_result)
|
24
|
+
return result.success unless result.success.nil?
|
25
|
+
raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'greeting failed: unknown result')
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class Processor
|
31
|
+
include ::Thrift::Processor
|
32
|
+
|
33
|
+
def process_greeting(seqid, iprot, oprot)
|
34
|
+
args = read_args(iprot, Greeting_args)
|
35
|
+
result = Greeting_result.new()
|
36
|
+
result.success = @handler.greeting(args.name)
|
37
|
+
write_result(result, oprot, 'greeting', seqid)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# HELPER FUNCTIONS AND STRUCTURES
|
43
|
+
|
44
|
+
class Greeting_args
|
45
|
+
include ::Thrift::Struct
|
46
|
+
NAME = 1
|
47
|
+
|
48
|
+
::Thrift::Struct.field_accessor self, :name
|
49
|
+
FIELDS = {
|
50
|
+
NAME => {:type => ::Thrift::Types::STRING, :name => 'name'}
|
51
|
+
}
|
52
|
+
|
53
|
+
def struct_fields; FIELDS; end
|
54
|
+
|
55
|
+
def validate
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class Greeting_result
|
61
|
+
include ::Thrift::Struct
|
62
|
+
SUCCESS = 0
|
63
|
+
|
64
|
+
::Thrift::Struct.field_accessor self, :success
|
65
|
+
FIELDS = {
|
66
|
+
SUCCESS => {:type => ::Thrift::Types::STRING, :name => 'success'}
|
67
|
+
}
|
68
|
+
|
69
|
+
def struct_fields; FIELDS; end
|
70
|
+
|
71
|
+
def validate
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Greeter
|
2
|
+
class Handler
|
3
|
+
def greeting(name)
|
4
|
+
"hello there #{name}!"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Server
|
9
|
+
def initialize(port)
|
10
|
+
@port = port
|
11
|
+
handler = Greeter::Handler.new
|
12
|
+
processor = Greeter::Processor.new(handler)
|
13
|
+
transport = Thrift::ServerSocket.new("127.0.0.1", port)
|
14
|
+
transportFactory = Thrift::FramedTransportFactory.new()
|
15
|
+
@server = Thrift::SimpleServer.new(processor, transport, transportFactory)
|
16
|
+
end
|
17
|
+
|
18
|
+
def serve
|
19
|
+
@server.serve()
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# client:
|
24
|
+
# trans = Thrift::HTTPClientTransport.new("http://127.0.0.1:9292/greeter")
|
25
|
+
# prot = Thrift::BinaryProtocol.new(trans)
|
26
|
+
# c = Greeter::Client.new(prot)
|
27
|
+
class HTTPServer
|
28
|
+
def initialize(uri)
|
29
|
+
uri = URI.parse(uri)
|
30
|
+
handler = Greeter::Handler.new
|
31
|
+
processor = Greeter::Processor.new(handler)
|
32
|
+
path = uri.path[1..-1]
|
33
|
+
@server = Thrift::MongrelHTTPServer.new(processor, :port => uri.port, :ip => uri.host, :path => path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def serve
|
37
|
+
@server.serve()
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/test/simple_test.rb
CHANGED
@@ -2,18 +2,18 @@
|
|
2
2
|
require "#{File.dirname(__FILE__)}/test_helper"
|
3
3
|
|
4
4
|
class SimpleTest < Test::Unit::TestCase
|
5
|
-
|
5
|
+
|
6
6
|
S = ThriftClient::Simple
|
7
7
|
S.make_struct("Example", S::Field.new(:name, S::STRING, 1))
|
8
8
|
S.make_struct("Args")
|
9
9
|
S.make_struct("Retval", S::Field.new(:rv, S::I32, 0))
|
10
|
-
|
10
|
+
|
11
11
|
def test_definition
|
12
12
|
assert Struct::ST_Example
|
13
13
|
assert Struct::ST_Args
|
14
14
|
assert Struct::ST_Retval
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
## Encoding
|
18
18
|
|
19
19
|
def test_boolean_encoding
|
@@ -69,7 +69,7 @@ class SimpleTest < Test::Unit::TestCase
|
|
69
69
|
assert_equal "\x80\x01\x00\x01\x00\x00\x00\x09getHeight\x00\x00\x00\x17\x00",
|
70
70
|
S.pack_request("getHeight", Struct::ST_Args.new, 23)
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
## Decoding
|
74
74
|
|
75
75
|
def test_boolean_decoding
|
@@ -133,5 +133,5 @@ class SimpleTest < Test::Unit::TestCase
|
|
133
133
|
StringIO.new("\x80\x01\x00\x02\x00\x00\x00\x09getHeight\x00\x00\x00\xff\x08\x00\x00\x00\x00\x00\x01\x00"),
|
134
134
|
Struct::ST_Retval)
|
135
135
|
end
|
136
|
-
|
136
|
+
|
137
137
|
end
|
data/test/test_helper.rb
CHANGED
@@ -4,5 +4,9 @@ require 'benchmark'
|
|
4
4
|
$LOAD_PATH << "#{File.expand_path(File.dirname(__FILE__))}/../lib"
|
5
5
|
require 'thrift_client'
|
6
6
|
require 'thrift_client/simple'
|
7
|
-
|
7
|
+
|
8
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__))
|
9
|
+
require 'greeter/greeter'
|
10
|
+
require 'greeter/server'
|
11
|
+
|
8
12
|
begin; require 'ruby-debug'; rescue LoadError; end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/test_helper"
|
2
|
+
require "thrift/server/mongrel_http_server"
|
3
|
+
|
4
|
+
class ThriftClientHTTPTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@servers = ["http://127.0.0.1:1461/greeter", "http://127.0.0.1:1462/greeter", "http://127.0.0.1:1463/greeter"]
|
8
|
+
@socket = 1461
|
9
|
+
@timeout = 0.2
|
10
|
+
@options = {:protocol_extra_params => [false]}
|
11
|
+
@pid = Process.fork do
|
12
|
+
Signal.trap("INT") { exit }
|
13
|
+
Greeter::HTTPServer.new(@servers.last).serve
|
14
|
+
end
|
15
|
+
# Need to give the child process a moment to open the listening socket or
|
16
|
+
# we get occasional "could not connect" errors in tests.
|
17
|
+
sleep 0.05
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
Process.kill("INT", @pid)
|
22
|
+
Process.wait
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_bad_uri
|
26
|
+
assert_raises URI::InvalidURIError do
|
27
|
+
@options.merge!({ :protocol => Thrift::BinaryProtocol, :transport => Thrift::HTTPClientTransport })
|
28
|
+
ThriftClient.new(Greeter::Client, "127.0.0.1:1463", @options).greeting("someone")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_bad_uri_no_http
|
33
|
+
assert_raises ArgumentError do
|
34
|
+
@options.merge!({ :protocol => Thrift::BinaryProtocol, :transport => Thrift::HTTPClientTransport })
|
35
|
+
ThriftClient.new(Greeter::Client, "//127.0.0.1:1463", @options).greeting("someone")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_valid_server
|
40
|
+
assert_nothing_raised do
|
41
|
+
@options.merge!({ :protocol => Thrift::BinaryProtocol, :transport => Thrift::HTTPClientTransport })
|
42
|
+
ThriftClient.new(Greeter::Client, "http://127.0.0.1:1463/greeter", @options).greeting("someone")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_non_random_fall_through
|
47
|
+
@servers = ["http://127.0.0.1:1463/greeter", "http://127.0.0.1:1461/greeter", "http://127.0.0.1:1462/greeter"]
|
48
|
+
assert_nothing_raised do
|
49
|
+
@options.merge!({ :protocol => Thrift::BinaryProtocol, :transport => Thrift::HTTPClientTransport })
|
50
|
+
ThriftClient.new(Greeter::Client, @servers, @options.merge(:randomize_server_list => false)).greeting("someone")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/test/thrift_client_test.rb
CHANGED
@@ -1,58 +1,74 @@
|
|
1
1
|
require "#{File.dirname(__FILE__)}/test_helper"
|
2
2
|
|
3
3
|
class ThriftClientTest < Test::Unit::TestCase
|
4
|
+
|
4
5
|
def setup
|
5
|
-
@entry = [ScribeThrift::LogEntry.new(:message => "something", :category => "thrift_client")]
|
6
6
|
@servers = ["127.0.0.1:1461", "127.0.0.1:1462", "127.0.0.1:1463"]
|
7
7
|
@socket = 1461
|
8
8
|
@timeout = 0.2
|
9
9
|
@options = {:protocol_extra_params => [false]}
|
10
|
+
@pid = Process.fork do
|
11
|
+
Signal.trap("INT") { exit }
|
12
|
+
Greeter::Server.new("1463").serve
|
13
|
+
end
|
14
|
+
# Need to give the child process a moment to open the listening socket or
|
15
|
+
# we get occasional "could not connect" errors in tests.
|
16
|
+
sleep 0.05
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
Process.kill("INT", @pid)
|
21
|
+
Process.wait
|
10
22
|
end
|
11
23
|
|
12
24
|
def test_live_server
|
13
25
|
assert_nothing_raised do
|
14
|
-
ThriftClient.new(
|
26
|
+
ThriftClient.new(Greeter::Client, @servers.last, @options).greeting("someone")
|
15
27
|
end
|
16
28
|
end
|
17
29
|
|
18
30
|
def test_non_random_fall_through
|
19
31
|
assert_nothing_raised do
|
20
|
-
ThriftClient.new(
|
32
|
+
ThriftClient.new(Greeter::Client, @servers, @options.merge(:randomize_server_list => false)).greeting("someone")
|
21
33
|
end
|
22
34
|
end
|
23
35
|
|
24
36
|
def test_dont_raise
|
25
37
|
assert_nothing_raised do
|
26
|
-
ThriftClient.new(
|
38
|
+
ThriftClient.new(Greeter::Client, @servers.first, @options.merge(:raise => false)).greeting("someone")
|
27
39
|
end
|
28
40
|
end
|
29
41
|
|
30
42
|
def test_dont_raise_with_defaults
|
31
|
-
client = ThriftClient.new(
|
32
|
-
assert_equal 1, client.
|
43
|
+
client = ThriftClient.new(Greeter::Client, @servers.first, @options.merge(:raise => false, :defaults => {:greeting => 1}))
|
44
|
+
assert_equal 1, client.greeting
|
33
45
|
end
|
34
46
|
|
35
47
|
def test_defaults_dont_override_no_method_error
|
36
|
-
client = ThriftClient.new(
|
37
|
-
assert_raises(NoMethodError) { client.Missing
|
48
|
+
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:raise => false, :defaults => {:Missing => 2}))
|
49
|
+
assert_raises(NoMethodError) { client.Missing }
|
38
50
|
end
|
39
51
|
|
40
52
|
def test_random_fall_through
|
41
53
|
assert_nothing_raised do
|
42
|
-
10.times
|
54
|
+
10.times do
|
55
|
+
client = ThriftClient.new(Greeter::Client, @servers, @options)
|
56
|
+
client.greeting("someone")
|
57
|
+
client.disconnect!
|
58
|
+
end
|
43
59
|
end
|
44
60
|
end
|
45
61
|
|
46
62
|
def test_lazy_connection
|
47
63
|
assert_nothing_raised do
|
48
|
-
ThriftClient.new(
|
64
|
+
ThriftClient.new(Greeter::Client, @servers[0,2])
|
49
65
|
end
|
50
66
|
end
|
51
67
|
|
52
68
|
def test_no_servers_eventually_raise
|
53
|
-
client = ThriftClient.new(
|
69
|
+
client = ThriftClient.new(Greeter::Client, @servers[0,2], @options)
|
54
70
|
assert_raises(ThriftClient::NoServersAvailable) do
|
55
|
-
client.
|
71
|
+
client.greeting("someone")
|
56
72
|
client.disconnect!
|
57
73
|
end
|
58
74
|
end
|
@@ -61,13 +77,12 @@ class ThriftClientTest < Test::Unit::TestCase
|
|
61
77
|
stub_server(@socket) do |socket|
|
62
78
|
measurement = Benchmark.measure do
|
63
79
|
assert_raises(Thrift::TransportException) do
|
64
|
-
ThriftClient.new(
|
80
|
+
ThriftClient.new(Greeter::Client, "127.0.0.1:#{@socket}",
|
65
81
|
@options.merge(:timeout => @timeout)
|
66
|
-
).
|
82
|
+
).greeting("someone")
|
67
83
|
end
|
68
84
|
end
|
69
|
-
assert((measurement.real > @timeout
|
70
|
-
assert((measurement.real < @timeout + 0.01), "#{measurement.real} > #{@timeout}")
|
85
|
+
assert((measurement.real > @timeout), "#{measurement.real} < #{@timeout}")
|
71
86
|
end
|
72
87
|
end
|
73
88
|
|
@@ -75,13 +90,12 @@ class ThriftClientTest < Test::Unit::TestCase
|
|
75
90
|
stub_server(@socket) do |socket|
|
76
91
|
measurement = Benchmark.measure do
|
77
92
|
assert_raises(Thrift::TransportException) do
|
78
|
-
ThriftClient.new(
|
79
|
-
@options.merge(:timeout => @timeout, :
|
80
|
-
).
|
93
|
+
ThriftClient.new(Greeter::Client, "127.0.0.1:#{@socket}",
|
94
|
+
@options.merge(:timeout => @timeout, :transport_wrapper => Thrift::BufferedTransport)
|
95
|
+
).greeting("someone")
|
81
96
|
end
|
82
97
|
end
|
83
|
-
assert((measurement.real > @timeout
|
84
|
-
assert((measurement.real < @timeout + 0.01), "#{measurement.real} > #{@timeout}")
|
98
|
+
assert((measurement.real > @timeout), "#{measurement.real} < #{@timeout}")
|
85
99
|
end
|
86
100
|
end
|
87
101
|
|
@@ -91,30 +105,29 @@ class ThriftClientTest < Test::Unit::TestCase
|
|
91
105
|
stub_server(@socket) do |socket|
|
92
106
|
measurement = Benchmark.measure do
|
93
107
|
assert_raises(Thrift::TransportException) do
|
94
|
-
ThriftClient.new(
|
95
|
-
@options.merge(:timeout => @timeout, :timeout_overrides => {:
|
96
|
-
).
|
108
|
+
ThriftClient.new(Greeter::Client, "127.0.0.1:#{@socket}",
|
109
|
+
@options.merge(:timeout => @timeout, :timeout_overrides => {:greeting => log_timeout}, :transport_wrapper => Thrift::BufferedTransport)
|
110
|
+
).greeting("someone")
|
97
111
|
end
|
98
112
|
end
|
99
|
-
assert((measurement.real > log_timeout
|
100
|
-
assert((measurement.real < log_timeout + 0.01), "#{measurement.real} > #{log_timeout}")
|
113
|
+
assert((measurement.real > log_timeout), "#{measurement.real} < #{log_timeout}")
|
101
114
|
end
|
102
115
|
end
|
103
116
|
|
104
117
|
def test_retry_period
|
105
|
-
client = ThriftClient.new(
|
106
|
-
assert_raises(ThriftClient::NoServersAvailable) { client.
|
118
|
+
client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:server_retry_period => 1))
|
119
|
+
assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
|
107
120
|
sleep 1.1
|
108
|
-
assert_raises(ThriftClient::NoServersAvailable) { client.
|
121
|
+
assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
|
109
122
|
end
|
110
|
-
|
123
|
+
|
111
124
|
def test_server_max_requests
|
112
|
-
client = ThriftClient.new(
|
113
|
-
client.
|
125
|
+
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:server_max_requests => 2))
|
126
|
+
client.greeting("someone")
|
114
127
|
internal_client = client.client
|
115
|
-
client.
|
128
|
+
client.greeting("someone")
|
116
129
|
assert_equal internal_client, client.client
|
117
|
-
client.
|
130
|
+
client.greeting("someone")
|
118
131
|
assert_not_equal internal_client, client.client
|
119
132
|
end
|
120
133
|
|
data/thrift_client.gemspec
CHANGED
@@ -2,22 +2,24 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{thrift_client}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.4.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0.8") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Evan Weaver"]
|
9
|
-
s.
|
9
|
+
s.cert_chain = ["/Users/ryan/.gemkeys/gem-public_cert.pem"]
|
10
|
+
s.date = %q{2010-02-18}
|
10
11
|
s.description = %q{A Thrift client wrapper that encapsulates some common failover behavior.}
|
11
12
|
s.email = %q{}
|
12
|
-
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "lib/thrift_client.rb", "lib/thrift_client/thrift.rb"]
|
13
|
-
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "lib/thrift_client.rb", "lib/thrift_client/thrift.rb", "test/
|
13
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc", "lib/thrift_client.rb", "lib/thrift_client/connection.rb", "lib/thrift_client/connection/base.rb", "lib/thrift_client/connection/factory.rb", "lib/thrift_client/connection/http.rb", "lib/thrift_client/connection/socket.rb", "lib/thrift_client/event_machine.rb", "lib/thrift_client/simple.rb", "lib/thrift_client/thrift.rb"]
|
14
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.rdoc", "Rakefile", "lib/thrift_client.rb", "lib/thrift_client/connection.rb", "lib/thrift_client/connection/base.rb", "lib/thrift_client/connection/factory.rb", "lib/thrift_client/connection/http.rb", "lib/thrift_client/connection/socket.rb", "lib/thrift_client/event_machine.rb", "lib/thrift_client/simple.rb", "lib/thrift_client/thrift.rb", "test/greeter/greeter.rb", "test/greeter/greeter.thrift", "test/greeter/server.rb", "test/simple_test.rb", "test/test_helper.rb", "test/thrift_client_http_test.rb", "test/thrift_client_test.rb", "thrift_client.gemspec"]
|
14
15
|
s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/thrift_client/}
|
15
|
-
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Thrift_client", "--main", "README"]
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Thrift_client", "--main", "README.rdoc"]
|
16
17
|
s.require_paths = ["lib"]
|
17
18
|
s.rubyforge_project = %q{fauna}
|
18
19
|
s.rubygems_version = %q{1.3.5}
|
20
|
+
s.signing_key = %q{/Users/ryan/.gemkeys/gem-private_key.pem}
|
19
21
|
s.summary = %q{A Thrift client wrapper that encapsulates some common failover behavior.}
|
20
|
-
s.test_files = ["test/simple_test.rb", "test/test_helper.rb", "test/thrift_client_test.rb"]
|
22
|
+
s.test_files = ["test/simple_test.rb", "test/test_helper.rb", "test/thrift_client_http_test.rb", "test/thrift_client_test.rb"]
|
21
23
|
|
22
24
|
if s.respond_to? :specification_version then
|
23
25
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
CHANGED
@@ -1,15 +1,36 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thrift_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Weaver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
|
-
cert_chain:
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMQ0wCwYDVQQDDARyeWFu
|
14
|
+
MRswGQYKCZImiZPyLGQBGRYLdGhlcnlhbmtpbmcxEzARBgoJkiaJk/IsZAEZFgNj
|
15
|
+
b20wHhcNMTAwMTA4MTc1MDM0WhcNMTEwMTA4MTc1MDM0WjBBMQ0wCwYDVQQDDARy
|
16
|
+
eWFuMRswGQYKCZImiZPyLGQBGRYLdGhlcnlhbmtpbmcxEzARBgoJkiaJk/IsZAEZ
|
17
|
+
FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLPp+0PtRT3qCI
|
18
|
+
02sMsADSn7Uf1GpyXUtk4Fb94LqUO6Scl91YDmbFMpjzrQwQvBYMIVreWcwSish6
|
19
|
+
nip6WEk9lqXcOeDmex/qY2/FVXG8ffqjFHiNiN9vpWrWj5VMICequ+ftzWLKsPIS
|
20
|
+
DGJ4o+Z6wEYRuirgaRPCYAUDPglsaqctJ56wPuycryMe5+ApSkOS9iLWMprQKEAq
|
21
|
+
j2R2OBV0dSARdbtzuKwrP7sLDo7uPa0egFBUlcZ+nujGr4LvmpryB8scNRNmZK1w
|
22
|
+
1rEI7O06CbULj08qYxEhnKmFE7LbBoN/HrmvZLVQK5mWuiZQhtmJuhBfStJsaDux
|
23
|
+
5tBEkYZVAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
|
24
|
+
BBSnLarDEo5eBE2arSMrBdOOhtrnPTANBgkqhkiG9w0BAQUFAAOCAQEANER07s4K
|
25
|
+
Pvc1DSduliRDMUax/VSfLzDTtTAQwuSAPDrWAYXKugcJtOZOXjDbGL7c5zoWmy9u
|
26
|
+
Fn5vEVdm/93J+84D/IMaaof3BwX/NNEYH01CeZEIGMfc5AFFha7dabzP/uiPpb/c
|
27
|
+
GSvomC9IzyN37+eWwOS16cC+5XnBT6KRCaXYg2Fh6WpTgde67OVgXr4Q58HXlaZ+
|
28
|
+
/2BB3wq9lZ4JskvlpYpYnlPAUyiyc6R2Mjts1pURz5nkW4SuS7Kd1KCOOyr1McDH
|
29
|
+
VP12sTSjJclmI17BjDGQpAF0n9v5ExhJxWpeOjeBUPQsOin3ypEM1KkckLmOKvH6
|
30
|
+
zyKMYVRO0z/58g==
|
31
|
+
-----END CERTIFICATE-----
|
11
32
|
|
12
|
-
date: 2010-
|
33
|
+
date: 2010-02-18 00:00:00 -08:00
|
13
34
|
default_executable:
|
14
35
|
dependencies:
|
15
36
|
- !ruby/object:Gem::Dependency
|
@@ -31,18 +52,37 @@ extensions: []
|
|
31
52
|
extra_rdoc_files:
|
32
53
|
- CHANGELOG
|
33
54
|
- LICENSE
|
34
|
-
- README
|
55
|
+
- README.rdoc
|
35
56
|
- lib/thrift_client.rb
|
57
|
+
- lib/thrift_client/connection.rb
|
58
|
+
- lib/thrift_client/connection/base.rb
|
59
|
+
- lib/thrift_client/connection/factory.rb
|
60
|
+
- lib/thrift_client/connection/http.rb
|
61
|
+
- lib/thrift_client/connection/socket.rb
|
62
|
+
- lib/thrift_client/event_machine.rb
|
63
|
+
- lib/thrift_client/simple.rb
|
36
64
|
- lib/thrift_client/thrift.rb
|
37
65
|
files:
|
38
66
|
- CHANGELOG
|
39
67
|
- LICENSE
|
40
68
|
- Manifest
|
41
|
-
- README
|
69
|
+
- README.rdoc
|
42
70
|
- Rakefile
|
43
71
|
- lib/thrift_client.rb
|
72
|
+
- lib/thrift_client/connection.rb
|
73
|
+
- lib/thrift_client/connection/base.rb
|
74
|
+
- lib/thrift_client/connection/factory.rb
|
75
|
+
- lib/thrift_client/connection/http.rb
|
76
|
+
- lib/thrift_client/connection/socket.rb
|
77
|
+
- lib/thrift_client/event_machine.rb
|
78
|
+
- lib/thrift_client/simple.rb
|
44
79
|
- lib/thrift_client/thrift.rb
|
80
|
+
- test/greeter/greeter.rb
|
81
|
+
- test/greeter/greeter.thrift
|
82
|
+
- test/greeter/server.rb
|
83
|
+
- test/simple_test.rb
|
45
84
|
- test/test_helper.rb
|
85
|
+
- test/thrift_client_http_test.rb
|
46
86
|
- test/thrift_client_test.rb
|
47
87
|
- thrift_client.gemspec
|
48
88
|
has_rdoc: true
|
@@ -56,7 +96,7 @@ rdoc_options:
|
|
56
96
|
- --title
|
57
97
|
- Thrift_client
|
58
98
|
- --main
|
59
|
-
- README
|
99
|
+
- README.rdoc
|
60
100
|
require_paths:
|
61
101
|
- lib
|
62
102
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -81,4 +121,5 @@ summary: A Thrift client wrapper that encapsulates some common failover behavior
|
|
81
121
|
test_files:
|
82
122
|
- test/simple_test.rb
|
83
123
|
- test/test_helper.rb
|
124
|
+
- test/thrift_client_http_test.rb
|
84
125
|
- test/thrift_client_test.rb
|
metadata.gz.sig
ADDED