module Semian::Redis

def connect

def connect
  acquire_semian_resource(adapter: :redis, scope: :connection) do
    raw_connect
  rescue SocketError, RuntimeError => e
    raise ResolveError, semian_identifier if dns_resolve_failure?(e.cause || e)
    raise
  end
end

def dns_resolve_failure?(e)

def dns_resolve_failure?(e)
  e.to_s.match?(/(can't resolve)|(name or service not known)|(nodename nor servname provided, or not known)|(failure in name resolution)/i) # rubocop:disable Layout/LineLength
end

def included(base)

The naked methods are exposed as `raw_query` and `raw_connect` for instrumentation purpose
def included(base)
  base.send(:alias_method, :raw_io, :io)
  base.send(:remove_method, :io)
  base.send(:alias_method, :raw_connect, :connect)
  base.send(:remove_method, :connect)
end

def io(&block)

def io(&block)
  acquire_semian_resource(adapter: :redis, scope: :query) do
    reply = raw_io(&block)
    raise_if_out_of_memory(reply)
    reply
  end
end

def raise_if_out_of_memory(reply)

def raise_if_out_of_memory(reply)
  return unless reply.is_a?(::Redis::CommandError)
  return unless reply.message =~ /OOM command not allowed when used memory > 'maxmemory'/
  raise ::Redis::OutOfMemoryError, reply.message
end

def raw_semian_options

def raw_semian_options
  return options[:semian] if options.key?(:semian)
  return options["semian"] if options.key?("semian")
end

def resource_exceptions

def resource_exceptions
  [
    ::Redis::BaseConnectionError,
    ::Errno::EINVAL, # Hiredis bug: https://github.com/redis/hiredis-rb/issues/21
    ::Redis::OutOfMemoryError,
  ]
end

def semian_identifier

def semian_identifier
  @semian_identifier ||= begin
    name = semian_options && semian_options[:name]
    name ||= "#{location}/#{db}"
    :"redis_#{name}"
  end
end

def with_resource_timeout(temp_timeout)

def with_resource_timeout(temp_timeout)
  timeout = options[:timeout]
  connect_timeout = options[:connect_timeout]
  read_timeout = options[:read_timeout]
  write_timeout = options[:write_timeout]
  begin
    connection.timeout = temp_timeout if connected?
    options[:timeout] = Float(temp_timeout)
    options[:connect_timeout] = Float(temp_timeout)
    options[:read_timeout] = Float(temp_timeout)
    options[:write_timeout] = Float(temp_timeout)
    yield
  ensure
    options[:timeout] = timeout
    options[:connect_timeout] = connect_timeout
    options[:read_timeout] = read_timeout
    options[:write_timeout] = write_timeout
    connection.timeout = self.timeout if connected?
  end
end