class Faulty::Storage::Memory

The default in-memory storage for circuits

This implementation is thread-safe and circuit state is shared across threads. Since state is stored in-memory, this state is not shared across processes, or persisted across application restarts.

Circuit state and runs are stored in memory. Although runs have a maximum size within a circuit, there is no limit on the number of circuits that can be stored. This means the user should be careful about the number of circuits that are created. To that end, it's a good idea to avoid dynamically-named circuits with this backend.

For a more robust distributed implementation, use the {Redis} storage backend.

This can be used as a reference implementation for storage backends that store a list of circuit run entries.

@todo Add a more sophsticated implmentation that can limit the number of

circuits stored.

Constants

MemoryCircuit

The internal object for storing a circuit

@private

Options

Options for {Memory}

@!attribute [r] max_sample_size

@return [Integer] The number of cache run entries to keep in memory
  for each circuit. Default `100`.

Attributes

options[R]

Public Class Methods

new(**options, &block) click to toggle source

@param options [Hash] Attributes for {Options} @yield [Options] For setting options in a block

# File lib/faulty/storage/memory.rb, line 76
def initialize(**options, &block)
  @circuits = Concurrent::Map.new
  @options = Options.new(options, &block)
end

Public Instance Methods

close(circuit) click to toggle source

Mark a circuit as closed

@see Interface#close @param (see Interface#close) @return (see Interface#close)

# File lib/faulty/storage/memory.rb, line 122
def close(circuit)
  memory = fetch(circuit)
  memory.runs.modify { |_old| [] }
  memory.state.compare_and_set(:open, :closed)
end
entry(circuit, time, success) click to toggle source

Add an entry to storage

@see Interface#entry @param (see Interface#entry) @return (see Interface#entry)

# File lib/faulty/storage/memory.rb, line 86
def entry(circuit, time, success)
  memory = fetch(circuit)
  memory.runs.borrow do |runs|
    runs.push([time, success])
    runs.shift if runs.size > options.max_sample_size
  end
  memory.runs.value
end
fault_tolerant?() click to toggle source

Memory storage is fault-tolerant by default

@return [true]

# File lib/faulty/storage/memory.rb, line 185
def fault_tolerant?
  true
end
history(circuit) click to toggle source

Get the circuit history up to `max_sample_size`

@see Interface#history @param (see Interface#history) @return (see Interface#history)

# File lib/faulty/storage/memory.rb, line 171
def history(circuit)
  fetch(circuit).runs.value
end
list() click to toggle source

Get a list of circuit names

@return [Array<String>] The circuit names

# File lib/faulty/storage/memory.rb, line 178
def list
  @circuits.keys
end
lock(circuit, state) click to toggle source

Lock a circuit open or closed

@see Interface#lock @param (see Interface#lock) @return (see Interface#lock)

# File lib/faulty/storage/memory.rb, line 133
def lock(circuit, state)
  memory = fetch(circuit)
  memory.lock = state
end
open(circuit, opened_at) click to toggle source

Mark a circuit as open

@see Interface#open @param (see Interface#open) @return (see Interface#open)

# File lib/faulty/storage/memory.rb, line 100
def open(circuit, opened_at)
  memory = fetch(circuit)
  opened = memory.state.compare_and_set(:closed, :open)
  memory.opened_at.reset(opened_at) if opened
  opened
end
reopen(circuit, opened_at, previous_opened_at) click to toggle source

Mark a circuit as reopened

@see Interface#reopen @param (see Interface#reopen) @return (see Interface#reopen)

# File lib/faulty/storage/memory.rb, line 112
def reopen(circuit, opened_at, previous_opened_at)
  memory = fetch(circuit)
  memory.opened_at.compare_and_set(previous_opened_at, opened_at)
end
reset(circuit) click to toggle source

Reset a circuit

@see Interface#reset @param (see Interface#reset) @return (see Interface#reset)

# File lib/faulty/storage/memory.rb, line 153
def reset(circuit)
  @circuits.delete(circuit.name)
end
status(circuit) click to toggle source

Get the status of a circuit

@see Interface#status @param (see Interface#status) @return (see Interface#status)

# File lib/faulty/storage/memory.rb, line 162
def status(circuit)
  fetch(circuit).status(circuit.options)
end
unlock(circuit) click to toggle source

Unlock a circuit

@see Interface#unlock @param (see Interface#unlock) @return (see Interface#unlock)

# File lib/faulty/storage/memory.rb, line 143
def unlock(circuit)
  memory = fetch(circuit)
  memory.lock = nil
end

Private Instance Methods

fetch(circuit) click to toggle source

Fetch circuit storage safely or create it if it doesn't exist

@return [MemoryCircuit]

# File lib/faulty/storage/memory.rb, line 194
def fetch(circuit)
  @circuits.compute_if_absent(circuit.name) { MemoryCircuit.new }
end