Module: Faulty::Patch::Redis

Includes:
Base
Included in:
Redis::Client
Defined in:
lib/faulty/patch/redis.rb,
lib/faulty/patch/redis/patch.rb,
lib/faulty/patch/redis/middleware.rb

Overview

Patch Redis to run all network IO in a circuit

This module is not required by default

Redis <= 4

Pass a :faulty key into your Redis connection options to enable circuit protection. See circuit_from_hash for the available options. On Redis 5+, the faulty key should be passed in the :custom hash instead of the top-level options. See example.

By default, all circuit errors raised by this patch inherit from ::Redis::BaseConnectionError

Examples:

require 'faulty/patch/redis'

# Redis <= 4
redis = Redis.new(url: 'redis://localhost:6379', faulty: {})
# Or for Redis 5+
redis = Redis.new(url: 'redis://localhost:6379', custom: { faulty: {} })

redis.connect # raises Faulty::CircuitError if connection fails

# If the faulty key is not given, no circuit is used
redis = Redis.new(url: 'redis://localhost:6379')
redis.connect # not protected by a circuit

See Also:

Defined Under Namespace

Modules: Middleware Classes: BusyError

Instance Method Summary collapse

Methods included from Base

#faulty_run

Instance Method Details

#call(command) ⇒ Object

Protect command calls



36
37
38
# File 'lib/faulty/patch/redis/patch.rb', line 36

def call(command)
  faulty_run { super }
end

#call_loop(command, timeout = 0) ⇒ Object

Protect command_loop calls



41
42
43
# File 'lib/faulty/patch/redis/patch.rb', line 41

def call_loop(command, timeout = 0)
  faulty_run { super }
end

#call_pipelined(commands) ⇒ Object

Protect pipelined commands



46
47
48
# File 'lib/faulty/patch/redis/patch.rb', line 46

def call_pipelined(commands)
  faulty_run { super }
end

#connectObject

The initial connection is protected by a circuit



31
32
33
# File 'lib/faulty/patch/redis/patch.rb', line 31

def connect
  faulty_run { super }
end

#initialize(options = {}) ⇒ Object

Patches Redis to add the :faulty key



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/faulty/patch/redis/patch.rb', line 16

def initialize(options = {})
  @faulty_circuit = Patch.circuit_from_hash(
    'redis',
    options[:faulty],
    errors: [
      ::Redis::BaseConnectionError,
      BusyError
    ],
    patched_error_mapper: Faulty::Patch::Redis
  )

  super
end

#io(&block) ⇒ Object

Inject specific error classes if client is patched

This method does not raise errors, it returns them as exception objects, so we simply modify that error if necessary and return it.

The call* methods above will then raise that error, so we are able to capture it with faulty_run.



58
59
60
61
62
63
64
65
66
67
# File 'lib/faulty/patch/redis/patch.rb', line 58

def io(&block)
  return super unless @faulty_circuit

  reply = super
  if reply.is_a?(::Redis::CommandError) && reply.message.start_with?('BUSY')
    reply = BusyError.new(reply.message)
  end

  reply
end