Error handling

Learn how to handle errors when using redis-rb.

redis-rb uses exceptions to signal errors. Most documentation examples focus on the "happy path", but production code should handle connection and command failures explicitly. This page explains how error handling works in redis-rb and how to apply common error handling patterns.

For an overview of error types and handling strategies, see Error handling.

Exception hierarchy

redis-rb organizes exceptions under Redis::BaseError:

"Redis::BaseError":
    _meta:
        description: "Base class for redis-rb exceptions"
    "Redis::ProtocolError":
    "Redis::CommandError":
        "Redis::PermissionError":
        "Redis::WrongTypeError":
        "Redis::OutOfMemoryError":
        "Redis::NoScriptError":
    "Redis::BaseConnectionError":
        "Redis::CannotConnectError":
        "Redis::ConnectionError":
        "Redis::TimeoutError":
        "Redis::ReadOnlyError":
    "...":
        _meta:
            ellipsis: true
            description: "Other redis-rb exception types"

Key exceptions

The following exceptions are the most commonly encountered in redis-rb applications. See Categories of errors for a more detailed discussion of these errors and their causes.

Exception When it occurs Recoverable Recommended action
Redis::CannotConnectError A connection could not be established Retry with backoff or fall back
Redis::TimeoutError A read or blocking operation timed out Retry with backoff and review timeouts
Redis::CommandError Redis returned an error reply such as ERR or WRONGTYPE Fix the command, arguments, or data model
Redis::ConnectionError An established connection was lost Reconnect and retry cautiously

Applying error handling patterns

The Error handling overview describes four main patterns. The sections below show how to implement them in redis-rb:

Pattern 1: Fail fast

Catch specific exceptions that represent unrecoverable errors and re-raise them (see Pattern 1: Fail fast for a full description):

begin
  redis.get(key)
rescue Redis::CommandError
  # This indicates a bug in our code or schema.
  raise
end

Pattern 2: Graceful degradation

Catch connection failures and fall back to an alternative (see Pattern 2: Graceful degradation for a full description):

begin
  cached_value = redis.get(key)
  return cached_value unless cached_value.nil?
rescue Redis::CannotConnectError, Redis::ConnectionError
  logger.warn("Cache unavailable, using database")
end

database.get(key)

Pattern 3: Retry with backoff

Retry on temporary errors such as timeouts (see Pattern 3: Retry with backoff for a full description):

delay = 0.1

3.times do |attempt|
  begin
    return redis.get(key)
  rescue Redis::CannotConnectError, Redis::ConnectionError, Redis::TimeoutError => e
    raise e if attempt == 2

    sleep(delay)
    delay *= 2
  end
end

Pattern 4: Log and continue

Log non-critical failures and continue (see Pattern 4: Log and continue for a full description):

begin
  redis.setex(key, 3600, value)
rescue Redis::CannotConnectError, Redis::ConnectionError, Redis::TimeoutError
  logger.warn("Failed to cache #{key}, continuing without cache")
end

Transaction conflicts

When a watched transaction in redis-rb loses an optimistic-locking race, multi() returns nil instead of raising an exception. Treat that as a retryable conflict:

result = redis.watch(key) do |client|
  current = client.get(key)

  client.multi do |tx|
    tx.set(key, current.upcase)
  end
end

retry_transaction if result.nil?

See also

RATE THIS PAGE
Back to top ↑