class Rester::Client
Attributes
adapter[R]
error_threshold[R]
logger[R]
retry_period[R]
version[R]
Public Class Methods
new(adapter, params={})
click to toggle source
# File lib/rester/client.rb, line 18 def initialize(adapter, params={}) self.adapter = adapter self.version = params[:version] @error_threshold = (params[:error_threshold] || 3).to_i @retry_period = (params[:retry_period] || 1).to_f self.logger = params[:logger] @_breaker_enabled = params.fetch(:circuit_breaker_enabled, ENV['RACK_ENV'] != 'test' && ENV['RAILS_ENV'] != 'test' ) @_resource = Resource.new(self) _init_requester # Send a test ping request to the service so we can store the producer's # name for future request logs fail Errors::ConnectionError unless connected? end
Public Instance Methods
circuit_breaker_enabled?()
click to toggle source
# File lib/rester/client.rb, line 43 def circuit_breaker_enabled? !!@_breaker_enabled end
connected?()
click to toggle source
# File lib/rester/client.rb, line 36 def connected? adapter.connected? && @_requester.call(:get, '/ping', {}).successful? rescue Exception => e logger.error("Connection Error: #{e.inspect}") false end
logger=(logger)
click to toggle source
# File lib/rester/client.rb, line 47 def logger=(logger) logger = Utils::LoggerWrapper.new(logger) if logger @logger = logger end
name()
click to toggle source
# File lib/rester/client.rb, line 56 def name @_producer_name end
request(verb, path, params={})
click to toggle source
# File lib/rester/client.rb, line 60 def request(verb, path, params={}) path = _path_with_version(path) @_requester.call(verb, path, params) rescue Utils::CircuitBreaker::CircuitOpenError # Translate this error so it's easier handle for clients. # Also, at some point we may want to extract CircuitBreaker into its own # gem, and this will make that easier. raise Errors::CircuitOpenError end
with_context(*args, &block)
click to toggle source
This is only implemented by the StubAdapter.
# File lib/rester/client.rb, line 72 def with_context(*args, &block) adapter.with_context(*args, &block) end
Protected Instance Methods
adapter=(adapter)
click to toggle source
# File lib/rester/client.rb, line 78 def adapter=(adapter) @adapter = adapter end
version=(version)
click to toggle source
# File lib/rester/client.rb, line 82 def version=(version) unless (@version = (version || 1).to_i) > 0 fail ArgumentError, 'version must be > 0' end end
Private Instance Methods
_init_requester()
click to toggle source
Sets up the circuit breaker for making requests to the service.
Any exception raised by the `_request` method will count as a failure for the circuit breaker. Once the threshold for errors has been reached, the circuit opens and all subsequent requests will raise a CircuitOpenError.
When the circuit is opened or closed, a message is sent to the logger for the client.
# File lib/rester/client.rb, line 105 def _init_requester if circuit_breaker_enabled? @_requester = Utils::CircuitBreaker.new( threshold: error_threshold, retry_period: retry_period ) { |*args| _request(*args) } @_requester.on_open do logger.error("circuit opened for #{name}") end @_requester.on_close do logger.info("circuit closed for #{name}") end else @_requester = proc { |*args| _request(*args) } end end
_parse_json(data)
click to toggle source
# File lib/rester/client.rb, line 179 def _parse_json(data) if data.is_a?(String) && !data.empty? JSON.parse(data, symbolize_names: true) else {} end end
_path_with_version(path)
click to toggle source
# File lib/rester/client.rb, line 153 def _path_with_version(path) Utils.join_paths("/v#{version}", path) end
_process_response(start_time, verb, path, status, headers, body)
click to toggle source
# File lib/rester/client.rb, line 157 def _process_response(start_time, verb, path, status, headers, body) elapsed_ms = (Time.now.to_f - start_time) * 1000 response = Response.new(status, _parse_json(body)) @_producer_name = headers['X-Rester-Producer-Name'] logger.info("received status #{status} after %0.3fms" % elapsed_ms) unless [200, 201, 400].include?(status) case status when 401 fail Errors::AuthenticationError when 403 fail Errors::ForbiddenError when 404 fail Errors::NotFoundError, path else fail Errors::ServerError, response[:message] end end response end
_request(verb, path, params)
click to toggle source
Add a correlation ID to the header and send the request to the adapter
# File lib/rester/client.rb, line 125 def _request(verb, path, params) Rester.wrap_request do Rester.request_info[:producer_name] = name Rester.request_info[:path] = path Rester.request_info[:verb] = verb logger.info('sending request') _set_default_headers start_time = Time.now.to_f begin response = adapter.request(verb, path, params) _process_response(start_time, verb, path, *response) rescue Errors::TimeoutError logger.error('timed out') raise end end end
_set_default_headers()
click to toggle source
# File lib/rester/client.rb, line 145 def _set_default_headers adapter.headers( 'X-Rester-Correlation-ID' => Rester.correlation_id, 'X-Rester-Consumer-Name' => Rester.service_name, 'X-Rester-Producer-Name' => name ) end
method_missing(meth, *args, &block)
click to toggle source
Submits the method to the adapter.
# File lib/rester/client.rb, line 92 def method_missing(meth, *args, &block) @_resource.send(:method_missing, meth, *args, &block) end