Class: RubyLLM::Resilience::MemoryStore

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_llm/resilience/memory_store.rb

Overview

Thread-safe in-process store implementing the five-method cache contract the breaker needs:

read(key)
write(key, value, expires_in: nil, unless_exist: false) -> true/false
increment(key, amount, expires_in: nil) -> Integer
delete(key)
delete_multi(keys)

This is the DEFAULT store and it is per-process: two Puma workers each see their own breaker state. That's fine for development and small deployments, but multi-process production apps should configure a shared store (e.g. ActiveSupport::Cache::RedisCacheStore) so a breaker tripped in one process is open in all of them.

TTL contract: increment applies expires_in only when it CREATES the counter; subsequent increments do not refresh the TTL. (This matches how the failure-counter window is meant to behave: N failures within the window of the first failure.)

Defined Under Namespace

Classes: Entry

Instance Method Summary collapse

Constructor Details

#initializeMemoryStore

Returns a new instance of MemoryStore.



27
28
29
30
# File 'lib/ruby_llm/resilience/memory_store.rb', line 27

def initialize
  @data = {}
  @mutex = Mutex.new
end

Instance Method Details

#clearObject



66
67
68
# File 'lib/ruby_llm/resilience/memory_store.rb', line 66

def clear
  @mutex.synchronize { @data.clear }
end

#delete(key) ⇒ Object



58
59
60
# File 'lib/ruby_llm/resilience/memory_store.rb', line 58

def delete(key)
  @mutex.synchronize { !@data.delete(key).nil? }
end

#delete_multi(keys) ⇒ Object



62
63
64
# File 'lib/ruby_llm/resilience/memory_store.rb', line 62

def delete_multi(keys)
  @mutex.synchronize { keys.count { |key| !@data.delete(key).nil? } }
end

#increment(key, amount = 1, expires_in: nil) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/ruby_llm/resilience/memory_store.rb', line 45

def increment(key, amount = 1, expires_in: nil)
  @mutex.synchronize do
    entry = live_entry(key)
    if entry
      entry.value = entry.value.to_i + amount
    else
      entry = Entry.new(amount, expires_in ? now + expires_in : nil)
      @data[key] = entry
    end
    entry.value
  end
end

#read(key) ⇒ Object



32
33
34
# File 'lib/ruby_llm/resilience/memory_store.rb', line 32

def read(key)
  @mutex.synchronize { live_entry(key)&.value }
end

#write(key, value, expires_in: nil, unless_exist: false) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/ruby_llm/resilience/memory_store.rb', line 36

def write(key, value, expires_in: nil, unless_exist: false)
  @mutex.synchronize do
    return false if unless_exist && live_entry(key)

    @data[key] = Entry.new(value, expires_in ? now + expires_in : nil)
    true
  end
end