Class: BreakerMachines::Storage::Cache

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

Overview

Storage adapter for ActiveSupport::Cache Works with any Rails cache store (Redis, Memcached, Memory, etc.)

Instance Method Summary collapse

Constructor Details

#initialize(cache_store: Rails.cache, **options) ⇒ Cache

Returns a new instance of Cache.



8
9
10
11
12
13
# File 'lib/breaker_machines/storage/cache.rb', line 8

def initialize(cache_store: Rails.cache, **options)
  super(**options)
  @cache = cache_store
  @prefix = options[:prefix] || 'breaker_machines'
  @expires_in = options[:expires_in] || 300 # 5 minutes default
end

Instance Method Details

#clear(circuit_name) ⇒ Object



53
54
55
56
57
58
# File 'lib/breaker_machines/storage/cache.rb', line 53

def clear(circuit_name)
  @cache.delete(status_key(circuit_name))
  @cache.delete(success_key(circuit_name))
  @cache.delete(failure_key(circuit_name))
  @cache.delete(events_key(circuit_name))
end

#clear_allObject



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/breaker_machines/storage/cache.rb', line 60

def clear_all
  # Clear all circuit data by pattern if cache supports it
  if @cache.respond_to?(:delete_matched)
    @cache.delete_matched("#{@prefix}:*")
  else
    # Fallback: can't efficiently clear all without pattern support
    BreakerMachines.logger&.warn(
      "[BreakerMachines] Cache store doesn't support delete_matched. " \
      'Individual circuit data must be cleared manually.'
    )
  end
end

#event_log(circuit_name, limit) ⇒ Object



92
93
94
95
# File 'lib/breaker_machines/storage/cache.rb', line 92

def event_log(circuit_name, limit)
  events = @cache.read(events_key(circuit_name)) || []
  events.last(limit)
end

#failure_count(circuit_name, window_seconds) ⇒ Object



49
50
51
# File 'lib/breaker_machines/storage/cache.rb', line 49

def failure_count(circuit_name, window_seconds)
  get_window_count(failure_key(circuit_name), window_seconds)
end

#get_status(circuit_name) ⇒ Object



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

def get_status(circuit_name)
  data = @cache.read(status_key(circuit_name))
  return nil unless data

  BreakerMachines::Status.new(
    status: data[:status].to_sym,
    opened_at: data[:opened_at]
  )
end

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



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/breaker_machines/storage/cache.rb', line 73

def record_event_with_details(circuit_name, type, duration, error: nil, new_state: nil)
  events = @cache.fetch(events_key(circuit_name)) { [] }

  event = {
    type: type,
    timestamp: monotonic_time,
    duration_ms: (duration * 1000).round(2)
  }

  event[:error_class] = error.class.name if error
  event[:error_message] = error.message if error
  event[:new_state] = new_state if new_state

  events << event
  events.shift while events.size > (@max_events || 100)

  @cache.write(events_key(circuit_name), events, expires_in: @expires_in)
end

#record_failure(circuit_name, _duration) ⇒ Object



41
42
43
# File 'lib/breaker_machines/storage/cache.rb', line 41

def record_failure(circuit_name, _duration)
  increment_counter(failure_key(circuit_name))
end

#record_success(circuit_name, _duration) ⇒ Object



37
38
39
# File 'lib/breaker_machines/storage/cache.rb', line 37

def record_success(circuit_name, _duration)
  increment_counter(success_key(circuit_name))
end

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



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/breaker_machines/storage/cache.rb', line 25

def set_status(circuit_name, status, opened_at = nil)
  @cache.write(
    status_key(circuit_name),
    {
      status: status,
      opened_at: opened_at,
      updated_at: monotonic_time
    },
    expires_in: @expires_in
  )
end

#success_count(circuit_name, window_seconds) ⇒ Object



45
46
47
# File 'lib/breaker_machines/storage/cache.rb', line 45

def success_count(circuit_name, window_seconds)
  get_window_count(success_key(circuit_name), window_seconds)
end

#with_timeout(_timeout_ms) ⇒ Object



97
98
99
100
101
102
# File 'lib/breaker_machines/storage/cache.rb', line 97

def with_timeout(_timeout_ms)
  # Rails cache operations should rely on their own underlying timeouts
  # Using Ruby's Timeout.timeout is dangerous and can cause deadlocks
  # For Redis cache stores, configure connect_timeout and read_timeout instead
  yield
end