Class: Faulty::Storage::Redis

Inherits:
Object
  • Object
show all
Defined in:
lib/faulty/storage/redis.rb

Overview

rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: Options

Constant Summary collapse

ENTRY_SEPARATOR =

Separates the time/status for history entry strings

':'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**options) {|Options| ... } ⇒ Redis

Returns a new instance of Redis.

Parameters:

  • options (Hash)

    Attributes for Options

Yields:

  • (Options)

    For setting options in a block



71
72
73
# File 'lib/faulty/storage/redis.rb', line 71

def initialize(**options, &block)
  @options = Options.new(options, &block)
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



9
10
11
# File 'lib/faulty/storage/redis.rb', line 9

def options
  @options
end

Instance Method Details

#close(circuit) ⇒ Boolean

Mark a circuit as closed

Returns:

  • (Boolean)

    True if the circuit transitioned from open to closed

See Also:



122
123
124
125
126
127
128
# File 'lib/faulty/storage/redis.rb', line 122

def close(circuit)
  redis do |r|
    closed = compare_and_set(r, state_key(circuit), ['open'], 'closed')
    r.del(entries_key(circuit)) if closed
    closed
  end
end

#entry(circuit, time, success) ⇒ Status

Add an entry to storage

Parameters:

  • circuit (Circuit)

    The circuit that ran

  • time (Integer)

    The unix timestamp for the run

  • success (Boolean)

    True if the run succeeded

Returns:

  • (Status)

    The circuit status after the run is added

See Also:



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/faulty/storage/redis.rb', line 80

def entry(circuit, time, success)
  key = entries_key(circuit)
  pipe do |r|
    r.sadd(list_key, circuit.name)
    r.expire(list_key, options.circuit_ttl + options.list_granularity) if options.circuit_ttl
    r.lpush(key, "#{time}#{ENTRY_SEPARATOR}#{success ? 1 : 0}")
    r.ltrim(key, 0, options.max_sample_size - 1)
    r.expire(key, options.sample_ttl) if options.sample_ttl
  end

  status(circuit)
end

#fault_tolerant?true

Redis storage is not fault-tolerant

Returns:

  • (true)


206
207
208
# File 'lib/faulty/storage/redis.rb', line 206

def fault_tolerant?
  false
end

#history(circuit) ⇒ Array<Array>

Get the circuit history up to max_sample_size

Parameters:

  • circuit (Circuit)

    The circuit to get history for

Returns:

  • (Array<Array>)

    An array of history tuples

See Also:



194
195
196
197
# File 'lib/faulty/storage/redis.rb', line 194

def history(circuit)
  entries = redis { |r| r.lrange(entries_key(circuit), 0, -1) }
  map_entries(entries).reverse
end

#listObject



199
200
201
# File 'lib/faulty/storage/redis.rb', line 199

def list
  redis { |r| r.sunion(*all_list_keys) }
end

#lock(circuit, state) ⇒ void

This method returns an undefined value.

Lock a circuit open or closed

The circuit_ttl does not apply to locks

Parameters:

  • circuit (Circuit)

    The circuit to lock

  • state (:open, :closed)

    The state to lock the circuit in

See Also:



137
138
139
# File 'lib/faulty/storage/redis.rb', line 137

def lock(circuit, state)
  redis { |r| r.set(lock_key(circuit), state) }
end

#open(circuit, opened_at) ⇒ Boolean

Mark a circuit as open

Parameters:

  • circuit (Circuit)

    The circuit to open

  • opened_at (Integer)

    The timestmp the circuit was opened at

Returns:

  • (Boolean)

    True if the circuit transitioned from closed to open

See Also:



98
99
100
101
102
103
104
# File 'lib/faulty/storage/redis.rb', line 98

def open(circuit, opened_at)
  redis do |r|
    opened = compare_and_set(r, state_key(circuit), ['closed', nil], 'open')
    r.set(opened_at_key(circuit), opened_at, ex: options.circuit_ttl) if opened
    opened
  end
end

#reopen(circuit, opened_at, previous_opened_at) ⇒ Boolean

Mark a circuit as reopened

Parameters:

  • circuit (Circuit)

    The circuit to reopen

  • opened_at (Integer)

    The timestmp the circuit was opened at

  • previous_opened_at (Integer)

    The last known value of opened_at. Can be used to comare-and-set.

Returns:

  • (Boolean)

    True if the opened_at time was updated

See Also:



111
112
113
114
115
# File 'lib/faulty/storage/redis.rb', line 111

def reopen(circuit, opened_at, previous_opened_at)
  redis do |r|
    compare_and_set(r, opened_at_key(circuit), [previous_opened_at.to_s], opened_at)
  end
end

#reset(circuit) ⇒ void

This method returns an undefined value.

Reset a circuit

Parameters:

  • circuit (Circuit)

    The circuit to unlock

See Also:



155
156
157
158
159
160
161
162
163
164
# File 'lib/faulty/storage/redis.rb', line 155

def reset(circuit)
  pipe do |r|
    r.del(
      entries_key(circuit),
      opened_at_key(circuit),
      lock_key(circuit)
    )
    r.set(state_key(circuit), 'closed', ex: options.circuit_ttl)
  end
end

#status(circuit) ⇒ Status

Get the status of a circuit

Parameters:

  • circuit (Circuit)

    The circuit to get status for

Returns:

  • (Status)

    The current status

See Also:



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/faulty/storage/redis.rb', line 171

def status(circuit)
  futures = {}
  pipe do |r|
    futures[:state] = r.get(state_key(circuit))
    futures[:lock] = r.get(lock_key(circuit))
    futures[:opened_at] = r.get(opened_at_key(circuit))
    futures[:entries] = r.lrange(entries_key(circuit), 0, -1)
  end

  Faulty::Status.from_entries(
    map_entries(futures[:entries].value),
    state: futures[:state].value&.to_sym || :closed,
    lock: futures[:lock].value&.to_sym,
    opened_at: futures[:opened_at].value ? futures[:opened_at].value.to_i : nil,
    options: circuit.options
  )
end

#unlock(circuit) ⇒ void

This method returns an undefined value.

Unlock a circuit

Parameters:

  • circuit (Circuit)

    The circuit to unlock

See Also:



146
147
148
# File 'lib/faulty/storage/redis.rb', line 146

def unlock(circuit)
  redis { |r| r.del(lock_key(circuit)) }
end