Class: SemanticCache::Stores::Redis

Inherits:
Object
  • Object
show all
Defined in:
lib/semantic_cache/stores/redis.rb

Overview

Redis-backed cache store. Suitable for production, multi-process, and distributed apps.

Requires the redis gem: gem install redis

Options:

max_size: Maximum number of entries to keep. When exceeded, the oldest
        entry (by created_at) is evicted. nil = unlimited.

Instance Method Summary collapse

Constructor Details

#initialize(redis: nil, namespace: nil, max_size: nil, **options) ⇒ Redis

Returns a new instance of Redis.



16
17
18
19
20
# File 'lib/semantic_cache/stores/redis.rb', line 16

def initialize(redis: nil, namespace: nil, max_size: nil, **options)
  @namespace = namespace || SemanticCache.configuration.namespace
  @redis = redis || connect(options)
  @max_size = max_size
end

Instance Method Details

#clearObject

Delete all entries.



87
88
89
90
91
92
93
94
95
# File 'lib/semantic_cache/stores/redis.rb', line 87

def clear
  keys = @redis.smembers(keys_set_key)
  keys&.each { |key| @redis.del(key) }
  @redis.del(keys_set_key)

  # Clean up tag indices
  tag_keys = @redis.keys("#{@namespace}:tag:*")
  tag_keys.each { |key| @redis.del(key) }
end

#delete(key) ⇒ Object

Delete a specific entry by key.



73
74
75
# File 'lib/semantic_cache/stores/redis.rb', line 73

def delete(key)
  delete_raw(namespaced_key(key))
end

#entriesObject

Retrieve all non-expired entries. Returns an Array of Entry objects.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/semantic_cache/stores/redis.rb', line 46

def entries
  keys = @redis.smembers(keys_set_key)
  return [] if keys.nil? || keys.empty?

  values = @redis.mget(*keys)
  result = []

  keys.each_with_index do |key, i|
    if values[i].nil?
      # Key expired in Redis; remove from set
      @redis.srem(keys_set_key, key)
      next
    end

    entry = Entry.from_json(values[i])
    if entry.expired?
      delete_raw(key)
      next
    end

    result << entry
  end

  result
end

#invalidate_by_tags(tags) ⇒ Object

Delete all entries matching the given tags.



78
79
80
81
82
83
84
# File 'lib/semantic_cache/stores/redis.rb', line 78

def invalidate_by_tags(tags)
  Array(tags).each do |tag|
    keys = @redis.smembers(tag_key(tag))
    keys&.each { |key| delete_raw(key) }
    @redis.del(tag_key(tag))
  end
end

#sizeObject

Number of entries in the store.



98
99
100
# File 'lib/semantic_cache/stores/redis.rb', line 98

def size
  @redis.scard(keys_set_key).to_i
end

#write(key, entry) ⇒ Object

Store a cache entry. Evicts the oldest entry if max_size is reached.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/semantic_cache/stores/redis.rb', line 23

def write(key, entry)
  evict_oldest! if @max_size && size >= @max_size

  full_key = namespaced_key(key)
  data = entry.to_json

  if entry.ttl
    @redis.setex(full_key, entry.ttl.to_i, data)
  else
    @redis.set(full_key, data)
  end

  # Maintain tag index
  entry.tags.each do |tag|
    @redis.sadd(tag_key(tag), full_key)
  end

  # Add to the set of all keys for scanning
  @redis.sadd(keys_set_key, full_key)
end