Class: BreakerMachines::Storage::FallbackChain

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

Overview

Apocalypse-resistant storage backend that tries multiple storage backends in sequence Falls back to the next storage backend when the current one times out or fails

NOTE: For DRb (distributed Ruby) environments, only :cache backend with external cache stores (Redis, Memcached) will work properly. Memory-based backends (:memory, :bucket_memory) are incompatible with DRb as they don’t share state between processes.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(storage_configs, circuit_breaker_threshold: 3, circuit_breaker_timeout: 30) ⇒ FallbackChain

Returns a new instance of FallbackChain.



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 14

def initialize(storage_configs, circuit_breaker_threshold: 3, circuit_breaker_timeout: 30, **)
  super(**)
  @storage_configs = normalize_storage_configs(storage_configs)
  @storage_instances = {}
  @circuit_breaker_threshold = circuit_breaker_threshold
  @circuit_breaker_timeout = circuit_breaker_timeout
  @backend_states = @storage_configs.to_h do |config|
    [config[:backend],
     BackendState.new(config[:backend], threshold: @circuit_breaker_threshold, timeout: @circuit_breaker_timeout)]
  end
  validate_configs!
end

Instance Attribute Details

#backend_statesObject (readonly)

Returns the value of attribute backend_states.



12
13
14
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 12

def backend_states
  @backend_states
end

#storage_configsObject (readonly)

Returns the value of attribute storage_configs.



12
13
14
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 12

def storage_configs
  @storage_configs
end

#storage_instancesObject (readonly)

Returns the value of attribute storage_instances.



12
13
14
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 12

def storage_instances
  @storage_instances
end

Instance Method Details

#cleanup!Object



73
74
75
76
77
78
79
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 73

def cleanup!
  storage_instances.each_value do |instance|
    instance.clear_all if instance.respond_to?(:clear_all)
  end
  storage_instances.clear
  backend_states.each_value(&:reset)
end

#clear(circuit_name) ⇒ Object



51
52
53
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 51

def clear(circuit_name)
  execute_with_fallback(:clear, circuit_name)
end

#clear_allObject



55
56
57
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 55

def clear_all
  execute_with_fallback(:clear_all)
end

#event_log(circuit_name, limit) ⇒ Object



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

def event_log(circuit_name, limit)
  execute_with_fallback(:event_log, circuit_name, limit)
end

#failure_count(circuit_name, window_seconds) ⇒ Object



47
48
49
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 47

def failure_count(circuit_name, window_seconds)
  execute_with_fallback(:failure_count, circuit_name, window_seconds)
end

#get_status(circuit_name) ⇒ Object



27
28
29
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 27

def get_status(circuit_name)
  execute_with_fallback(:get_status, circuit_name)
end

#record_event_with_details(circuit_name, type, duration, error: nil, new_state: nil) ⇒ Object



59
60
61
62
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 59

def record_event_with_details(circuit_name, type, duration, error: nil, new_state: nil)
  execute_with_fallback(:record_event_with_details, circuit_name, type, duration, error: error,
                                                                                  new_state: new_state)
end

#record_failure(circuit_name, duration) ⇒ Object



39
40
41
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 39

def record_failure(circuit_name, duration)
  execute_with_fallback(:record_failure, circuit_name, duration)
end

#record_success(circuit_name, duration) ⇒ Object



35
36
37
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 35

def record_success(circuit_name, duration)
  execute_with_fallback(:record_success, circuit_name, duration)
end

#set_status(circuit_name, status, opened_at = nil) ⇒ Object



31
32
33
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 31

def set_status(circuit_name, status, opened_at = nil)
  execute_with_fallback(:set_status, circuit_name, status, opened_at)
end

#success_count(circuit_name, window_seconds) ⇒ Object



43
44
45
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 43

def success_count(circuit_name, window_seconds)
  execute_with_fallback(:success_count, circuit_name, window_seconds)
end

#with_timeout(_timeout_ms) ⇒ Object



68
69
70
71
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 68

def with_timeout(_timeout_ms)
  # FallbackChain doesn't use timeout directly - each backend handles its own
  yield
end