thrift_client 0.3.3 → 0.4.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.
- 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