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) ⇒ FallbackChain

Returns a new instance of FallbackChain.



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

def initialize(storage_configs, **)
  super(**)
  @storage_configs = normalize_storage_configs(storage_configs)
  @storage_instances = {}
  @unhealthy_until = {}
  @circuit_breaker_threshold = 3 # After 3 failures, mark backend as unhealthy
  @circuit_breaker_timeout = 30 # Keep marked as unhealthy for 30 seconds
  validate_configs!
end

Instance Attribute Details

#circuit_breaker_thresholdObject (readonly)

Returns the value of attribute circuit_breaker_threshold.



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

def circuit_breaker_threshold
  @circuit_breaker_threshold
end

#circuit_breaker_timeoutObject (readonly)

Returns the value of attribute circuit_breaker_timeout.



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

def circuit_breaker_timeout
  @circuit_breaker_timeout
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

#unhealthy_untilObject (readonly)

Returns the value of attribute unhealthy_until.



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

def unhealthy_until
  @unhealthy_until
end

Instance Method Details

#cleanup!Object



70
71
72
73
74
75
76
77
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 70

def cleanup!
  storage_instances.each_value do |instance|
    instance.clear_all if instance.respond_to?(:clear_all)
  end
  storage_instances.clear
  @backend_failures&.clear
  unhealthy_until.clear
end

#clear(circuit_name) ⇒ Object



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

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

#clear_allObject



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

def clear_all
  execute_with_fallback(:clear_all)
end

#event_log(circuit_name, limit) ⇒ Object



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

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

#failure_count(circuit_name, window_seconds) ⇒ Object



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

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

#get_status(circuit_name) ⇒ Object



24
25
26
# File 'lib/breaker_machines/storage/fallback_chain.rb', line 24

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



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

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



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

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

#record_success(circuit_name, duration) ⇒ Object



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

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

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



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

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



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

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

#with_timeout(_timeout_ms) ⇒ Object



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

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