thrift_client 0.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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