class RedisClient

Constants

AuthenticationError
CannotConnectError
CheckoutTimeoutError
ConnectionError
FailoverError
MasterDownError
OutOfMemoryError
PermissionError
ProtocolError
ReadOnlyError
ReadTimeoutError
TimeoutError
UnsupportedServer
VERSION
WriteTimeoutError
WrongTypeError

Public Class Methods

config(**kwargs) click to toggle source
# File lib/redis_client.rb, line 165
def config(**kwargs)
  Config.new(client_implementation: self, **kwargs)
end
default_driver() click to toggle source
# File lib/redis_client.rb, line 33
def default_driver
  unless @default_driver
    @driver_definitions.each_key do |name|
      if @default_driver = driver(name)
        break
      end
    rescue LoadError
    end
  end
  @default_driver
end
default_driver=(name) click to toggle source
# File lib/redis_client.rb, line 45
def default_driver=(name)
  @default_driver = driver(name)
end
driver(name) click to toggle source
# File lib/redis_client.rb, line 22
def driver(name)
  return name if name.is_a?(Class)

  name = name.to_sym
  unless @driver_definitions.key?(name)
    raise ArgumentError, "Unknown driver #{name.inspect}, expected one of: `#{@driver_definitions.keys.inspect}`"
  end

  @drivers[name] ||= @driver_definitions[name]&.call
end
new(arg = nil, **kwargs) click to toggle source
Calls superclass method RedisClient::Common::new
# File lib/redis_client.rb, line 173
def new(arg = nil, **kwargs)
  if arg.is_a?(Config::Common)
    super
  else
    super(config(**(arg || {}), **kwargs))
  end
end
new(config, **) click to toggle source
Calls superclass method RedisClient::Common::new
# File lib/redis_client.rb, line 188
def initialize(config, **)
  super
  @middlewares = config.middlewares_stack.new(self)
  @raw_connection = nil
  @disable_reconnection = false
end
register(middleware) click to toggle source
# File lib/redis_client.rb, line 181
def register(middleware)
  Middlewares.include(middleware)
end
register_driver(name, &block) click to toggle source
# File lib/redis_client.rb, line 18
def register_driver(name, &block)
  @driver_definitions[name] = block
end
sentinel(**kwargs) click to toggle source
# File lib/redis_client.rb, line 169
def sentinel(**kwargs)
  SentinelConfig.new(client_implementation: self, **kwargs)
end

Public Instance Methods

blocking_call(timeout, *command, **kwargs) { |result| ... } click to toggle source
# File lib/redis_client.rb, line 335
def blocking_call(timeout, *command, **kwargs)
  command = @command_builder.generate(command, kwargs)
  error = nil
  result = ensure_connected do |connection|
    @middlewares.call(command, config) do
      connection.call(command, timeout)
    end
  rescue ReadTimeoutError => error
    break
  end

  if error
    raise error
  elsif block_given?
    yield result
  else
    result
  end
end
blocking_call_v(timeout, command) { |result| ... } click to toggle source
# File lib/redis_client.rb, line 355
def blocking_call_v(timeout, command)
  command = @command_builder.generate(command)
  error = nil
  result = ensure_connected do |connection|
    @middlewares.call(command, config) do
      connection.call(command, timeout)
    end
  rescue ReadTimeoutError => error
    break
  end

  if error
    raise error
  elsif block_given?
    yield result
  else
    result
  end
end
call(*command, **kwargs) { |result| ... } click to toggle source
# File lib/redis_client.rb, line 275
def call(*command, **kwargs)
  command = @command_builder.generate(command, kwargs)
  result = ensure_connected do |connection|
    @middlewares.call(command, config) do
      connection.call(command, nil)
    end
  end

  if block_given?
    yield result
  else
    result
  end
end
call_once(*command, **kwargs) { |result| ... } click to toggle source
# File lib/redis_client.rb, line 305
def call_once(*command, **kwargs)
  command = @command_builder.generate(command, kwargs)
  result = ensure_connected(retryable: false) do |connection|
    @middlewares.call(command, config) do
      connection.call(command, nil)
    end
  end

  if block_given?
    yield result
  else
    result
  end
end
call_once_v(command) { |result| ... } click to toggle source
# File lib/redis_client.rb, line 320
def call_once_v(command)
  command = @command_builder.generate(command)
  result = ensure_connected(retryable: false) do |connection|
    @middlewares.call(command, config) do
      connection.call(command, nil)
    end
  end

  if block_given?
    yield result
  else
    result
  end
end
call_v(command) { |result| ... } click to toggle source
# File lib/redis_client.rb, line 290
def call_v(command)
  command = @command_builder.generate(command)
  result = ensure_connected do |connection|
    @middlewares.call(command, config) do
      connection.call(command, nil)
    end
  end

  if block_given?
    yield result
  else
    result
  end
end
close() click to toggle source
# File lib/redis_client.rb, line 415
def close
  @raw_connection&.close
  self
end
connected?() click to toggle source
# File lib/redis_client.rb, line 411
def connected?
  @raw_connection&.revalidate
end
db() click to toggle source
# File lib/redis_client.rb, line 212
def db
  config.db
end
disable_reconnection(&block) click to toggle source
# File lib/redis_client.rb, line 420
def disable_reconnection(&block)
  ensure_connected(retryable: false, &block)
end
host() click to toggle source
# File lib/redis_client.rb, line 216
def host
  config.host unless config.path
end
hscan(key, *args, **kwargs, &block) click to toggle source
# File lib/redis_client.rb, line 393
def hscan(key, *args, **kwargs, &block)
  unless block_given?
    return to_enum(__callee__, key, *args, **kwargs)
  end

  args = @command_builder.generate(["HSCAN", key, 0] + args, kwargs)
  scan_pairs(2, args, &block)
end
id() click to toggle source
# File lib/redis_client.rb, line 204
def id
  config.id
end
inspect() click to toggle source
# File lib/redis_client.rb, line 195
def inspect
  id_string = " id=#{id}" if id
  "#<#{self.class.name} #{config.server_url}#{id_string}>"
end
measure_round_trip_delay() click to toggle source
# File lib/redis_client.rb, line 267
def measure_round_trip_delay
  ensure_connected do |connection|
    @middlewares.call(["PING"], config) do
      connection.measure_round_trip_delay
    end
  end
end
multi(watch: nil, &block) click to toggle source
# File lib/redis_client.rb, line 442
def multi(watch: nil, &block)
  transaction = nil

  results = if watch
    # WATCH is stateful, so we can't reconnect if it's used, the whole transaction
    # has to be redone.
    ensure_connected(retryable: false) do |connection|
      call("WATCH", *watch)
      begin
        if transaction = build_transaction(&block)
          commands = transaction._commands
          results = @middlewares.call_pipelined(commands, config) do
            connection.call_pipelined(commands, nil)
          end.last
        else
          call("UNWATCH")
          []
        end
      rescue
        call("UNWATCH") if connected? && watch
        raise
      end
    end
  else
    transaction = build_transaction(&block)
    if transaction._empty?
      []
    else
      ensure_connected(retryable: transaction._retryable?) do |connection|
        commands = transaction._commands
        @middlewares.call_pipelined(commands, config) do
          connection.call_pipelined(commands, nil)
        end.last
      end
    end
  end

  if transaction
    transaction._coerce!(results)
  else
    results
  end
end
password() click to toggle source
# File lib/redis_client.rb, line 232
def password
  config.password
end
path() click to toggle source
# File lib/redis_client.rb, line 224
def path
  config.path
end
pipelined(exception: true) { |pipeline| ... } click to toggle source
# File lib/redis_client.rb, line 424
def pipelined(exception: true)
  pipeline = Pipeline.new(@command_builder)
  yield pipeline

  if pipeline._size == 0
    []
  else
    results = ensure_connected(retryable: pipeline._retryable?) do |connection|
      commands = pipeline._commands
      @middlewares.call_pipelined(commands, config) do
        connection.call_pipelined(commands, pipeline._timeouts, exception: exception)
      end
    end

    pipeline._coerce!(results)
  end
end
port() click to toggle source
# File lib/redis_client.rb, line 220
def port
  config.port unless config.path
end
pubsub() click to toggle source
# File lib/redis_client.rb, line 261
def pubsub
  sub = PubSub.new(ensure_connected, @command_builder)
  @raw_connection = nil
  sub
end
read_timeout=(timeout) click to toggle source
Calls superclass method
# File lib/redis_client.rb, line 251
def read_timeout=(timeout)
  super
  @raw_connection&.read_timeout = timeout
end
scan(*args, **kwargs, &block) click to toggle source
# File lib/redis_client.rb, line 375
def scan(*args, **kwargs, &block)
  unless block_given?
    return to_enum(__callee__, *args, **kwargs)
  end

  args = @command_builder.generate(["SCAN", 0] + args, kwargs)
  scan_list(1, args, &block)
end
server_url() click to toggle source
# File lib/redis_client.rb, line 200
def server_url
  config.server_url
end
size() click to toggle source
# File lib/redis_client.rb, line 236
def size
  1
end
sscan(key, *args, **kwargs, &block) click to toggle source
# File lib/redis_client.rb, line 384
def sscan(key, *args, **kwargs, &block)
  unless block_given?
    return to_enum(__callee__, key, *args, **kwargs)
  end

  args = @command_builder.generate(["SSCAN", key, 0] + args, kwargs)
  scan_list(2, args, &block)
end
then(_options = nil)
Alias for: with
timeout() click to toggle source
# File lib/redis_client.rb, line 208
def timeout
  config.read_timeout
end
timeout=(timeout) click to toggle source
Calls superclass method RedisClient::Common#timeout=
# File lib/redis_client.rb, line 245
def timeout=(timeout)
  super
  @raw_connection&.read_timeout = timeout
  @raw_connection&.write_timeout = timeout
end
username() click to toggle source
# File lib/redis_client.rb, line 228
def username
  config.username
end
with(_options = nil) { |self| ... } click to toggle source
# File lib/redis_client.rb, line 240
def with(_options = nil)
  yield self
end
Also aliased as: then
write_timeout=(timeout) click to toggle source
Calls superclass method
# File lib/redis_client.rb, line 256
def write_timeout=(timeout)
  super
  @raw_connection&.write_timeout = timeout
end
zscan(key, *args, **kwargs, &block) click to toggle source
# File lib/redis_client.rb, line 402
def zscan(key, *args, **kwargs, &block)
  unless block_given?
    return to_enum(__callee__, key, *args, **kwargs)
  end

  args = @command_builder.generate(["ZSCAN", key, 0] + args, kwargs)
  scan_pairs(2, args, &block)
end

Private Instance Methods

build_transaction() { |transaction| ... } click to toggle source
# File lib/redis_client.rb, line 649
def build_transaction
  transaction = Multi.new(@command_builder)
  transaction.call("MULTI")
  yield transaction
  transaction.call("EXEC")
  transaction
end
connect() click to toggle source
# File lib/redis_client.rb, line 737
def connect
  @pid = PIDCache.pid

  if @raw_connection
    @middlewares.connect(config) do
      @raw_connection.reconnect
    end
  else
    @raw_connection = @middlewares.connect(config) do
      config.driver.new(
        config,
        connect_timeout: connect_timeout,
        read_timeout: read_timeout,
        write_timeout: write_timeout,
      )
    end
  end

  prelude = config.connection_prelude.dup

  if id
    prelude << ["CLIENT", "SETNAME", id]
  end

  # The connection prelude is deliberately not sent to Middlewares
  if config.sentinel?
    prelude << ["ROLE"]
    role, = @middlewares.call_pipelined(prelude, config) do
      @raw_connection.call_pipelined(prelude, nil).last
    end
    config.check_role!(role)
  else
    unless prelude.empty?
      @middlewares.call_pipelined(prelude, config) do
        @raw_connection.call_pipelined(prelude, nil)
      end
    end
  end
rescue FailoverError, CannotConnectError => error
  error._set_config(config)
  raise error
rescue ConnectionError => error
  connect_error = CannotConnectError.with_config(error.message, config)
  connect_error.set_backtrace(error.backtrace)
  raise connect_error
rescue CommandError => error
  if error.message.match?(/ERR unknown command ['`]HELLO['`]/)
    raise UnsupportedServer,
      "redis-client requires Redis 6+ with HELLO command available (#{config.server_url})"
  else
    raise
  end
end
ensure_connected(retryable: true) { |raw_connection| ... } click to toggle source
# File lib/redis_client.rb, line 683
def ensure_connected(retryable: true)
  close if !config.inherit_socket && @pid != PIDCache.pid

  if @disable_reconnection
    if block_given?
      yield @raw_connection
    else
      @raw_connection
    end
  elsif retryable
    tries = 0
    connection = nil
    preferred_error = nil
    begin
      connection = raw_connection
      if block_given?
        yield connection
      else
        connection
      end
    rescue ConnectionError, ProtocolError => error
      preferred_error ||= error
      preferred_error = error unless error.is_a?(CircuitBreaker::OpenCircuitError)
      close

      if !@disable_reconnection && config.retry_connecting?(tries, error)
        tries += 1
        retry
      else
        raise preferred_error
      end
    end
  else
    previous_disable_reconnection = @disable_reconnection
    connection = ensure_connected
    begin
      @disable_reconnection = true
      yield connection
    rescue ConnectionError, ProtocolError
      close
      raise
    ensure
      @disable_reconnection = previous_disable_reconnection
    end
  end
end
raw_connection() click to toggle source
# File lib/redis_client.rb, line 730
def raw_connection
  if @raw_connection.nil? || !@raw_connection.revalidate
    connect
  end
  @raw_connection
end
scan_list(cursor_index, command, &block) click to toggle source
# File lib/redis_client.rb, line 657
def scan_list(cursor_index, command, &block)
  cursor = 0
  while cursor != "0"
    command[cursor_index] = cursor
    cursor, elements = call(*command)
    elements.each(&block)
  end
  nil
end
scan_pairs(cursor_index, command) { |elements, elements| ... } click to toggle source
# File lib/redis_client.rb, line 667
def scan_pairs(cursor_index, command)
  cursor = 0
  while cursor != "0"
    command[cursor_index] = cursor
    cursor, elements = call(*command)

    index = 0
    size = elements.size
    while index < size
      yield elements[index], elements[index + 1]
      index += 2
    end
  end
  nil
end