thrift_client 0.3 → 0.3.1

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.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,4 +1,6 @@
1
1
 
2
+ v0.3.1. Add ability to reset connection after N requests.
3
+
2
4
  v0.3. Change default timeout semantics; hash default was too sneaky. Fix bug.
3
5
 
4
6
  v0.2.2. Fix connect bug.
data/lib/thrift_client.rb CHANGED
@@ -30,12 +30,13 @@ class ThriftClient
30
30
  :raise => true,
31
31
  :retries => nil,
32
32
  :server_retry_period => 1,
33
+ :server_max_requests => nil,
33
34
  :timeout => 1,
34
35
  :timeout_overrides => {},
35
36
  :defaults => {}
36
37
  }.freeze
37
38
 
38
- attr_reader :client, :client_class, :server_list, :options
39
+ attr_reader :client, :client_class, :current_server, :server_list, :options
39
40
 
40
41
  =begin rdoc
41
42
  Create a new ThriftClient instance. Accepts an internal Thrift client class (such as CassandraRb::Client), a list of servers with ports, and optional parameters.
@@ -49,8 +50,9 @@ Valid optional parameters are:
49
50
  <tt>:raise</tt>:: Whether to reraise errors if no responsive servers are found. Defaults to <tt>true</tt>.
50
51
  <tt>:retries</tt>:: How many times to retry a request. Defaults to the number of servers defined.
51
52
  <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.
52
- <tt>:timeout</tt>:: Specify the default timeout for every call. Defaults to <tt>.
53
- <tt>:timeout_overrides</tt>:: Specify timeouts on a per-method basis. Only work with <tt>Thrift::BufferedTransport</tt>.
53
+ <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).
54
+ <tt>:timeout</tt>:: Specify the default timeout in seconds. Defaults to <tt>1</tt>.
55
+ <tt>:timeout_overrides</tt>:: Specify additional timeouts on a per-method basis, in seconds. Only works with <tt>Thrift::BufferedTransport</tt>.
54
56
  <tt>:defaults</tt>:: Specify default values to return on a per-method basis, if <tt>:raise</tt> is set to false.
55
57
 
56
58
  =end rdoc
@@ -60,7 +62,6 @@ Valid optional parameters are:
60
62
  @client_class = client_class
61
63
  @server_list = Array(servers)
62
64
  @retries = options[:retries] || @server_list.size
63
- @server_list = @server_list.sort_by { rand } if @options[:randomize_server_list]
64
65
 
65
66
  if @options[:timeout_overrides].any?
66
67
  if @options[:transport].instance_methods.include?("timeout=")
@@ -69,9 +70,11 @@ Valid optional parameters are:
69
70
  warn "ThriftClient: Timeout overrides have no effect with with transport type #{@options[:transport]}"
70
71
  end
71
72
  end
72
-
73
- @live_server_list = @server_list.dup
74
- @last_retry = Time.now
73
+
74
+ @request_count = 0
75
+ @max_requests = @options[:server_max_requests]
76
+ @retry_period = @options[:server_retry_period]
77
+ rebuild_live_server_list!
75
78
 
76
79
  @client_class.instance_methods.each do |method_name|
77
80
  if method_name =~ /^recv_(.*)$/
@@ -82,37 +85,51 @@ Valid optional parameters are:
82
85
 
83
86
  # Force the client to connect to the server.
84
87
  def connect!
85
- server = next_server.to_s.split(":")
86
- raise ArgumentError, 'Servers must be in the form "host:port"' if server.size != 2
88
+ server = next_server
89
+ host, port = server.to_s.split(":")
90
+ raise ArgumentError, 'Servers must be in the form "host:port"' unless host and port
87
91
 
88
92
  @transport = @options[:transport].new(
89
- Thrift::Socket.new(server.first, server.last.to_i, @options[:timeout]))
93
+ Thrift::Socket.new(host, port.to_i, @options[:timeout]))
90
94
  @transport.open
95
+ @current_server = server
91
96
  @client = @client_class.new(@options[:protocol].new(@transport, *@options[:protocol_extra_params]))
92
97
  rescue Thrift::TransportException
93
98
  retry
94
99
  end
95
100
 
96
101
  # Force the client to disconnect from the server.
97
- def disconnect!
102
+ def disconnect!(keep = true)
98
103
  @transport.close rescue nil
104
+
105
+ # Keep live servers in the list if we have a retry period. Otherwise,
106
+ # always eject, because we will always re-add them.
107
+ if keep and @retry_period and @current_server
108
+ @live_server_list.unshift(@current_server)
109
+ end
110
+
111
+ @request_count = 0
99
112
  @client = nil
113
+ @current_server = nil
100
114
  end
101
115
 
102
116
  private
103
117
 
104
118
  def proxy(method_name, *args)
119
+ disconnect! if @max_requests and @request_count >= @max_requests
105
120
  connect! unless @client
121
+
106
122
  set_timeout!(method_name) if @set_timeout
123
+ @request_count += 1
107
124
  @client.send(method_name, *args)
108
125
  rescue NoServersAvailable => e
109
126
  handle_exception(e, method_name, args)
110
127
  rescue *@options[:exception_classes] => e
111
- tries ||= @retries
128
+ tries ||= @retries
112
129
  if (tries -= 1) == 0
113
130
  handle_exception(e, method_name, args)
114
131
  else
115
- disconnect!
132
+ disconnect!(false)
116
133
  retry
117
134
  end
118
135
  end
@@ -127,13 +144,21 @@ Valid optional parameters are:
127
144
  end
128
145
 
129
146
  def next_server
130
- if @live_server_list.empty?
131
- if @options[:server_retry_period] and Time.now < @last_retry + @options[:server_retry_period]
132
- raise NoServersAvailable, "No live servers in #{@server_list.inspect} since #{@last_retry.inspect}."
133
- end
134
- @last_retry = Time.now
135
- @live_server_list = @server_list.dup
147
+ if @retry_period
148
+ rebuild_live_server_list! if Time.now > @last_rebuild + @retry_period
149
+ raise NoServersAvailable, "No live servers in #{@server_list.inspect} since #{@last_rebuild.inspect}." if @live_server_list.empty?
150
+ elsif @live_server_list.empty?
151
+ rebuild_live_server_list!
136
152
  end
137
153
  @live_server_list.pop
138
154
  end
155
+
156
+ def rebuild_live_server_list!
157
+ @last_rebuild = Time.now
158
+ if @options[:randomize_server_list]
159
+ @live_server_list = @server_list.sort_by { rand }
160
+ else
161
+ @live_server_list = @server_list.dup
162
+ end
163
+ end
139
164
  end
@@ -26,23 +26,17 @@ class ThriftClientTest < Test::Unit::TestCase
26
26
  ThriftClient.new(ScribeThrift::Client, @servers.first, @options.merge(:raise => false)).Log(@entry)
27
27
  end
28
28
  end
29
-
29
+
30
30
  def test_dont_raise_with_defaults
31
31
  client = ThriftClient.new(ScribeThrift::Client, @servers.first, @options.merge(:raise => false, :defaults => {:Log => 1}))
32
32
  assert_equal 1, client.Log(@entry)
33
33
  end
34
-
34
+
35
35
  def test_defaults_dont_override_no_method_error
36
36
  client = ThriftClient.new(ScribeThrift::Client, @servers, @options.merge(:raise => false, :defaults => {:Missing => 2}))
37
- assert_raises(NoMethodError) { client.Missing(@entry) }
37
+ assert_raises(NoMethodError) { client.Missing(@entry) }
38
38
  end
39
39
 
40
- def test_random_server_list
41
- @lists = []
42
- @lists << ThriftClient.new(ScribeThrift::Client, @servers, @options).server_list while @lists.size < 10
43
- assert @lists.uniq.size > 1
44
- end
45
-
46
40
  def test_random_fall_through
47
41
  assert_nothing_raised do
48
42
  10.times { ThriftClient.new(ScribeThrift::Client, @servers, @options).Log(@entry) }
@@ -62,35 +56,35 @@ class ThriftClientTest < Test::Unit::TestCase
62
56
  client.disconnect!
63
57
  end
64
58
  end
65
-
59
+
66
60
  def test_framed_transport_timeout
67
61
  stub_server(@socket) do |socket|
68
62
  measurement = Benchmark.measure do
69
63
  assert_raises(Thrift::TransportException) do
70
- ThriftClient.new(ScribeThrift::Client, "127.0.0.1:#{@socket}",
64
+ ThriftClient.new(ScribeThrift::Client, "127.0.0.1:#{@socket}",
71
65
  @options.merge(:timeout => @timeout)
72
- ).Log(@entry)
66
+ ).Log(@entry)
73
67
  end
74
68
  end
75
69
  assert((measurement.real > @timeout - 0.01), "#{measurement.real} < #{@timeout}")
76
70
  assert((measurement.real < @timeout + 0.01), "#{measurement.real} > #{@timeout}")
77
71
  end
78
72
  end
79
-
73
+
80
74
  def test_buffered_transport_timeout
81
75
  stub_server(@socket) do |socket|
82
76
  measurement = Benchmark.measure do
83
77
  assert_raises(Thrift::TransportException) do
84
78
  ThriftClient.new(ScribeThrift::Client, "127.0.0.1:#{@socket}",
85
79
  @options.merge(:timeout => @timeout, :transport => Thrift::BufferedTransport)
86
- ).Log(@entry)
80
+ ).Log(@entry)
87
81
  end
88
82
  end
89
83
  assert((measurement.real > @timeout - 0.01), "#{measurement.real} < #{@timeout}")
90
84
  assert((measurement.real < @timeout + 0.01), "#{measurement.real} > #{@timeout}")
91
85
  end
92
- end
93
-
86
+ end
87
+
94
88
  def test_buffered_transport_timeout_override
95
89
  # FIXME Large timeout values always are applied twice for some bizarre reason
96
90
  log_timeout = @timeout * 4
@@ -99,7 +93,7 @@ class ThriftClientTest < Test::Unit::TestCase
99
93
  assert_raises(Thrift::TransportException) do
100
94
  ThriftClient.new(ScribeThrift::Client, "127.0.0.1:#{@socket}",
101
95
  @options.merge(:timeout => @timeout, :timeout_overrides => {:Log => log_timeout}, :transport => Thrift::BufferedTransport)
102
- ).Log(@entry)
96
+ ).Log(@entry)
103
97
  end
104
98
  end
105
99
  assert((measurement.real > log_timeout - 0.01), "#{measurement.real} < #{log_timeout }")
@@ -114,13 +108,23 @@ class ThriftClientTest < Test::Unit::TestCase
114
108
  assert_raises(ThriftClient::NoServersAvailable) { client.Log(@entry) }
115
109
  end
116
110
 
111
+ def test_server_max_requests
112
+ client = ThriftClient.new(ScribeThrift::Client, @servers, @options.merge(:server_max_requests => 2))
113
+ client.Log(@entry)
114
+ internal_client = client.client
115
+ client.Log(@entry)
116
+ assert_equal internal_client, client.client
117
+ client.Log(@entry)
118
+ assert_not_equal internal_client, client.client
119
+ end
120
+
117
121
  private
118
-
122
+
119
123
  def stub_server(port)
120
124
  socket = TCPServer.new('127.0.0.1', port)
121
125
  Thread.new { socket.accept }
122
126
  yield socket
123
127
  ensure
124
128
  socket.close
125
- end
129
+ end
126
130
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{thrift_client}
5
- s.version = "0.3"
5
+ s.version = "0.3.1"
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"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thrift_client
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.3"
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Weaver
metadata.gz.sig CHANGED
Binary file