docbrown/app/services/search/client.rb
2020-05-18 10:36:01 -05:00

65 lines
2.1 KiB
Ruby

module Search
# Search client (uses Elasticsearch as a backend)
class Client
class << self
# adapted from https://api.rubyonrails.org/classes/Module.html#method-i-delegate_missing_to
def method_missing(method, *args, &block)
return super unless target.respond_to?(method, false)
# define for re-use
self.class.define_method(method) do |*new_args, &new_block|
request do
target.public_send(method, *new_args, &new_block)
end
end
# call the original method, this will only be called the first time
# as in subsequent calls, the newly defined method will prevail
request do
target.public_send(method, *args, &block)
end
end
# adapted from https://api.rubyonrails.org/classes/Module.html#method-i-delegate_missing_to
def respond_to_missing?(method, _include_all = false)
target.respond_to?(method, false) || super
end
private
TRANSPORT_EXCEPTIONS = [
Elasticsearch::Transport::Transport::Errors::BadRequest,
Elasticsearch::Transport::Transport::Errors::NotFound,
].freeze
def request
yield
rescue *TRANSPORT_EXCEPTIONS => e
class_name = e.class.name.demodulize
record_error(e.message, class_name)
# raise specific error if known, generic one if unknown
error_class = "::Search::Errors::Transport::#{class_name}".safe_constantize
raise error_class, e.message if error_class
raise ::Search::Errors::TransportError, e.message
end
def record_error(error_message, class_name)
Honeycomb.add_field("elasticsearch.result", "error")
Honeycomb.add_field("elasticsearch.error", class_name)
DatadogStatsClient.increment("elasticsearch.errors", tags: ["error:#{class_name}", "message:#{error_message}"])
end
def target
@target ||= Elasticsearch::Client.new(
url: ApplicationConfig["ELASTICSEARCH_URL"],
retry_on_failure: 5,
request_timeout: 30,
adapter: :patron,
log: Rails.env.development?,
)
end
end
end
end