Class: Faulty::Storage::FallbackChain

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

Overview

An prioritized list of storage backends

If any backend fails, the next will be tried until one succeeds. This should typically be used when using a fault-prone backend such as Redis.

This is used by Faulty#initialize if the storage option is set to an array.

Examples:

# This storage will try Redis first, then fallback to memory storage
# if Redis is unavailable.
storage = Faulty::Storage::FallbackChain.new([
  Faulty::Storage::Redis.new,
  Faulty::Storage::Memory.new
])

Defined Under Namespace

Classes: Options

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(storages, **options) {|Options| ... } ⇒ FallbackChain

Create a new Faulty::Storage::FallbackChain to automatically fallback to reliable storage

Parameters:

  • storages (Array<Storage::Interface>)

    An array of storage backends. The primary storage should be specified first. If that one fails, additional entries will be tried in sequence until one succeeds.

  • options (Hash)

    Attributes for Options

Yields:

  • (Options)

    For setting options in a block



45
46
47
48
# File 'lib/faulty/storage/fallback_chain.rb', line 45

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

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



22
23
24
# File 'lib/faulty/storage/fallback_chain.rb', line 22

def options
  @options
end

Instance Method Details

#clearvoid

This method returns an undefined value.

Clears circuits in all storage backends



176
177
178
# File 'lib/faulty/storage/fallback_chain.rb', line 176

def clear
  send_all(:clear)
end

#close(circuit) ⇒ Boolean

Close a circuit in the first available storage backend

Returns:

  • (Boolean)

    True if the circuit transitioned from open to closed



102
103
104
105
106
# File 'lib/faulty/storage/fallback_chain.rb', line 102

def close(circuit)
  send_chain(:close, circuit) do |e|
    options.notifier.notify(:storage_failure, circuit: circuit, action: :close, error: e)
  end
end

#entry(circuit, time, success, status) ⇒ Status?

Create a circuit entry in the first available storage backend

Parameters:

  • circuit (Circuit)

    The circuit that ran

  • time (Float)

    The unix timestamp for the run, from Faulty.current_time

  • success (Boolean)

    True if the run succeeded

  • status (Status, nil)

    The previous status. If given, this method must return an updated status object from the new entry data.

Returns:

  • (Status, nil)

    If status is not nil, the updated status object.



72
73
74
75
76
# File 'lib/faulty/storage/fallback_chain.rb', line 72

def entry(circuit, time, success, status)
  send_chain(:entry, circuit, time, success, status) do |e|
    options.notifier.notify(:storage_failure, circuit: circuit, action: :entry, error: e)
  end
end

#fault_tolerant?Boolean

This is fault tolerant if any of the available backends are fault tolerant

Returns:

  • (Boolean)

    True if this cache backend is fault tolerant



184
185
186
# File 'lib/faulty/storage/fallback_chain.rb', line 184

def fault_tolerant?
  @storages.any?(&:fault_tolerant?)
end

#get_options(circuit) ⇒ Hash

Get options from the first available storage backend

Returns:

  • (Hash)

    A hash of the options stored by #set_options. The keys must be symbols.



54
55
56
57
58
# File 'lib/faulty/storage/fallback_chain.rb', line 54

def get_options(circuit)
  send_chain(:get_options, circuit) do |e|
    options.notifier.notify(:storage_failure, circuit: circuit, action: :get_options, error: e)
  end
end

#history(circuit) ⇒ Array<Array>

Get the history of a circuit from the first available storage backend

Parameters:

  • circuit (Circuit)

    The circuit to get history for

Returns:

  • (Array<Array>)

    An array of history tuples



156
157
158
159
160
# File 'lib/faulty/storage/fallback_chain.rb', line 156

def history(circuit)
  send_chain(:history, circuit) do |e|
    options.notifier.notify(:storage_failure, circuit: circuit, action: :history, error: e)
  end
end

#listArray<String>

Get the list of circuits from the first available storage backend

Returns:

  • (Array<String>)


166
167
168
169
170
# File 'lib/faulty/storage/fallback_chain.rb', line 166

def list
  send_chain(:list) do |e|
    options.notifier.notify(:storage_failure, action: :list, error: e)
  end
end

#lock(circuit, state) ⇒ void

This method returns an undefined value.

Lock a circuit in all storage backends

Parameters:

  • circuit (Circuit)

    The circuit to lock

  • state (:open, :closed)

    The state to lock the circuit in



122
123
124
# File 'lib/faulty/storage/fallback_chain.rb', line 122

def lock(circuit, state)
  send_all(:lock, circuit, state)
end

#open(circuit, opened_at) ⇒ Boolean

Open a circuit in the first available storage backend

Parameters:

  • circuit (Circuit)

    The circuit to open

  • opened_at (Float)

    The timestamp the circuit was opened at, from Faulty.current_time

Returns:

  • (Boolean)

    True if the circuit transitioned from closed to open



82
83
84
85
86
# File 'lib/faulty/storage/fallback_chain.rb', line 82

def open(circuit, opened_at)
  send_chain(:open, circuit, opened_at) do |e|
    options.notifier.notify(:storage_failure, circuit: circuit, action: :open, error: e)
  end
end

#reopen(circuit, opened_at, previous_opened_at) ⇒ Boolean

Reopen a circuit in the first available storage backend

Parameters:

  • circuit (Circuit)

    The circuit to reopen

  • opened_at (Float)

    The timestamp the circuit was opened at, from Faulty.current_time

  • previous_opened_at (Float)

    The last known value of opened_at. Can be used to compare-and-set. Always non-nil — Circuit#failure! only enters the reopen branch when status.half_open? is true, which requires non-nil opened_at. Unlike previous_reserved_at on #reserve, there is no legitimate "no prior value" call path to reopen, so backends may treat this parameter as required and are not expected to handle nil.

Returns:

  • (Boolean)

    True if the opened_at time was updated



92
93
94
95
96
# File 'lib/faulty/storage/fallback_chain.rb', line 92

def reopen(circuit, opened_at, previous_opened_at)
  send_chain(:reopen, circuit, opened_at, previous_opened_at) do |e|
    options.notifier.notify(:storage_failure, circuit: circuit, action: :reopen, error: e)
  end
end

#reserve(circuit, reserved_at, previous_reserved_at) ⇒ Boolean

Reserve a half-open run in the first available storage backend

Parameters:

  • circuit (Circuit)

    The circuit to reserve

  • reserved_at (Float)

    The timestamp of this reservation, from Faulty.current_time

  • previous_reserved_at (Float, nil)

    The last known value of reserved_at, or nil for the first reservation in a new open cycle. Can be used to compare-and-set.

Returns:

  • (Boolean)

    True if the caller may proceed with the half-open test run; false if another caller already holds the reservation.



112
113
114
115
116
# File 'lib/faulty/storage/fallback_chain.rb', line 112

def reserve(circuit, reserved_at, previous_reserved_at)
  send_chain(:reserve, circuit, reserved_at, previous_reserved_at) do |e|
    options.notifier.notify(:storage_failure, circuit: circuit, action: :reserve, error: e)
  end
end

#reset(circuit) ⇒ void

This method returns an undefined value.

Reset a circuit in all storage backends

Parameters:

  • circuit (Circuit)

    The circuit to unlock



138
139
140
# File 'lib/faulty/storage/fallback_chain.rb', line 138

def reset(circuit)
  send_all(:reset, circuit)
end

#set_options(circuit, stored_options) ⇒ void

This method returns an undefined value.

Try to set circuit options on all backends

Parameters:

  • circuit (Circuit)

    The circuit to set options for

  • stored_options (Hash<Symbol, Object>)

    A hash of symbol option names to circuit options. These option values are guranteed to be primive values.



64
65
66
# File 'lib/faulty/storage/fallback_chain.rb', line 64

def set_options(circuit, stored_options)
  send_all(:set_options, circuit, stored_options)
end

#status(circuit) ⇒ Status

Get the status of a circuit from the first available storage backend

Parameters:

  • circuit (Circuit)

    The circuit to get status for

Returns:

  • (Status)

    The current status



146
147
148
149
150
# File 'lib/faulty/storage/fallback_chain.rb', line 146

def status(circuit)
  send_chain(:status, circuit) do |e|
    options.notifier.notify(:storage_failure, circuit: circuit, action: :status, error: e)
  end
end

#unlock(circuit) ⇒ void

This method returns an undefined value.

Unlock a circuit in all storage backends

Parameters:

  • circuit (Circuit)

    The circuit to unlock



130
131
132
# File 'lib/faulty/storage/fallback_chain.rb', line 130

def unlock(circuit)
  send_all(:unlock, circuit)
end