class AbstractThriftClient

Constants

DEFAULTS
DEFAULT_WRAPPED_ERRORS
DISCONNECT_ERRORS

Attributes

client[R]
client_class[R]
client_methods[R]
current_server[R]
last_client[R]
options[R]
server_list[R]

Public Class Methods

create_wrapped_exception_classes(client_class, wrapped_exception_classes = DEFAULT_WRAPPED_ERRORS) click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 38
def self.create_wrapped_exception_classes(client_class, wrapped_exception_classes = DEFAULT_WRAPPED_ERRORS)
  wrapped_exception_classes.map do |exception_klass|
    name = exception_klass.to_s.split('::').last
    begin
      client_class.const_get(name)
    rescue NameError
      client_class.const_set(name, Class.new(exception_klass))
    end
  end
end
new(client_class, servers, options = {}) click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 49
def initialize(client_class, servers, options = {})
  @options = DEFAULTS.merge(options)
  @options[:server_retry_period] ||= 0

  @client_class = client_class
  @server_list = Array(servers).collect do |s|
    Server.new(s, @client_class, @options)
  end.sort_by { rand }

  @current_server = @server_list.first

  @callbacks = {}
  @client_methods = []
  @client_class.instance_methods.each do |method_name|
    if method_name != 'send_message' && method_name =~ /^send_(.*)$/
      instance_eval("def #{$1}(*args); handled_proxy(:'#{$1}', *args); end", __FILE__, __LINE__)
      @client_methods << $1
    end
  end
  @request_count = 0
  self.class.create_wrapped_exception_classes(@client_class, @options[:wrapped_exception_classes])
end

Public Instance Methods

add_callback(callback_type, &block) click to toggle source

Adds a callback that will be invoked at a certain time. The valid callback types are:

:post_connect  - should accept a single AbstractThriftClient argument, which is the client object to
                 which the callback was added. Called after a connection to the remote thrift server
                 is established.
:before_method - should accept a single method name argument. Called before a method is invoked on the
                 thrift server.
:on_exception  - should accept 2 args: an Exception instance and a method name. Called right before the
                 exception is raised.
# File lib/thrift_client/abstract_thrift_client.rb, line 80
def add_callback(callback_type, &block)
  case callback_type
  when :post_connect, :before_method, :on_exception
    @callbacks[callback_type] ||= []
    @callbacks[callback_type].push(block)
    # Allow chaining
    return self
  else
    return nil
  end
end
connect!(method = nil) click to toggle source

Force the client to connect to the server. Not necessary to be called as the connection will be made on the first RPC method call.

# File lib/thrift_client/abstract_thrift_client.rb, line 99
def connect!(method = nil)
  start_time ||= Time.now
  @current_server = next_live_server
  @client = @current_server.client
  @last_client = @client
  do_callbacks(:post_connect, self)
rescue IOError, Thrift::TransportException
  disconnect!(true)
  timeout = timeout(method)
  if timeout && Time.now - start_time > timeout
    no_servers_available!
  else
    retry
  end
end
disconnect!(error = false) click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 115
def disconnect!(error = false)
  if @current_server
    @current_server.mark_down!(@options[:server_retry_period]) if error
    @current_server.close
  end

  @client = nil
  @current_server = nil
  @request_count = 0
end
inspect() click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 92
def inspect
  "<#{self.class}(#{client_class}) @current_server=#{@current_server}>"
end

Private Instance Methods

do_callbacks(callback_type_sym, *args) click to toggle source

Calls all callbacks of the specified type with the given args

# File lib/thrift_client/abstract_thrift_client.rb, line 129
def do_callbacks(callback_type_sym, *args)
  return unless @callbacks[callback_type_sym]
  @callbacks[callback_type_sym].each do |callback|
    callback.call(*args)
  end
end
ensure_socket_alignment() { || ... } click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 148
def ensure_socket_alignment
  incomplete = true
  result = yield
  incomplete = false
  result
# Thrift exceptions get read off the wire. We can consider them complete requests
rescue Thrift::Exception => e
  incomplete = false
  raise e
ensure
  disconnect! if incomplete
end
handled_proxy(method_name, *args) click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 161
def handled_proxy(method_name, *args)
  begin
    connect!(method_name.to_sym) unless @client
    if has_timeouts?
      @client.timeout = timeout(method_name.to_sym)
    end
    @request_count += 1
    do_callbacks(:before_method, method_name)
    ensure_socket_alignment { @client.send(method_name, *args) }
  rescue *@options[:exception_class_overrides] => e
    raise_or_default(e, method_name)
  rescue *@options[:exception_classes] => e
    disconnect!(true)
    tries ||= (@options[:retry_overrides][method_name.to_sym] || @options[:retries]) + 1
    tries -= 1
    if tries > 0
      retry
    else
      raise_or_default(e, method_name)
    end
  rescue Exception => e
    raise_or_default(e, method_name)
  ensure
    disconnect! if @options[:server_max_requests] && @request_count >= @options[:server_max_requests]
  end
end
has_timeouts?() click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 205
def has_timeouts?
  @has_timeouts ||= @options[:timeout_overrides].any? && transport_can_timeout?
end
next_live_server() click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 136
def next_live_server
  @server_index ||= 0
  @server_list.length.times do |i|
    cur = (1 + @server_index + i) % @server_list.length
    if @server_list[cur].up?
      @server_index = cur
      return @server_list[cur]
    end
  end
  no_servers_available!
end
no_servers_available!() click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 222
def no_servers_available!
  servers = @server_list.map { |s| s.to_s }.join(',')
  raise ThriftClient::NoServersAvailable, "No live servers in [#{servers}]."
end
raise_or_default(e, method_name) click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 188
def raise_or_default(e, method_name)
  if @options[:raise]
    raise_wrapped_error(e, method_name)
  else
    @options[:defaults][method_name.to_sym]
  end
end
raise_wrapped_error(e, method_name) click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 196
def raise_wrapped_error(e, method_name)
  do_callbacks(:on_exception, e, method_name)
  if @options[:wrapped_exception_classes].include?(e.class)
    raise @client_class.const_get(e.class.to_s.split('::').last), e.message, e.backtrace
  else
    raise e
  end
end
timeout(method = nil) click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 209
def timeout(method = nil)
  @options[:timeout_overrides][method] || @options[:timeout]
end
transport_can_timeout?() click to toggle source
# File lib/thrift_client/abstract_thrift_client.rb, line 213
def transport_can_timeout?
  if (@options[:transport_wrapper] || @options[:transport]).method_defined?(:timeout=)
    true
  else
    warn "ThriftClient: Timeout overrides have no effect with with transport type #{(@options[:transport_wrapper] || @options[:transport])}"
    false
  end
end