Class: Woods::Cache::RedisCacheStore

Inherits:
CacheStore show all
Defined in:
lib/woods/cache/redis_cache_store.rb

Overview

Redis-backed cache store using GET/SET with TTL.

Uses simple key-value operations (not Lists like SessionTracer::RedisStore). Values are JSON-serialized on write and deserialized on read. TTL is enforced natively by Redis via the EX option on SET.

Requires the ‘redis` gem at runtime.

Examples:

store = RedisCacheStore.new(redis: Redis.new, default_ttl: 3600)
store.write("ci:emb:abc", [0.1, 0.2], ttl: 86_400)
store.read("ci:emb:abc") # => [0.1, 0.2]

Instance Method Summary collapse

Methods inherited from CacheStore

#fetch

Constructor Details

#initialize(redis:, default_ttl: nil) ⇒ RedisCacheStore

Returns a new instance of RedisCacheStore.

Parameters:

  • redis (Redis)

    A Redis client instance

  • default_ttl (Integer, nil) (defaults to: nil)

    Default TTL in seconds when none specified (nil = no expiry)

Raises:



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

def initialize(redis:, default_ttl: nil)
  super()
  unless defined?(::Redis)
    raise ConfigurationError,
          'The redis gem is required for RedisCacheStore. Add `gem "redis"` to your Gemfile.'
  end

  @redis = redis
  @default_ttl = default_ttl
end

Instance Method Details

#clear(namespace: nil) ⇒ void

This method returns an undefined value.

Clear cached entries by namespace or all woods cache keys.

Uses SCAN (not KEYS) to avoid blocking Redis on large keyspaces.

Parameters:

  • namespace (Symbol, nil) (defaults to: nil)

    Domain to clear, or nil for all cache keys



101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/woods/cache/redis_cache_store.rb', line 101

def clear(namespace: nil)
  pattern = clear_pattern(namespace)

  cursor = '0'
  loop do
    cursor, keys = @redis.scan(cursor, match: pattern, count: 100)
    @redis.del(*keys) if keys.any?
    break if cursor == '0'
  end
rescue ::Redis::BaseError, Errno::ECONNREFUSED, Errno::ECONNRESET => e
  logger.warn("[Woods] RedisCacheStore#clear failed: #{e.message}")
  nil
end

#delete(key) ⇒ void

This method returns an undefined value.

Delete a key from Redis.

Parameters:

  • key (String)

    Cache key



77
78
79
80
81
82
# File 'lib/woods/cache/redis_cache_store.rb', line 77

def delete(key)
  @redis.del(key)
rescue ::Redis::BaseError, Errno::ECONNREFUSED, Errno::ECONNRESET => e
  logger.warn("[Woods] RedisCacheStore#delete failed for #{key}: #{e.message}")
  nil
end

#exist?(key) ⇒ Boolean

Check if a key exists in Redis.

Parameters:

  • key (String)

    Cache key

Returns:

  • (Boolean)


88
89
90
91
92
93
# File 'lib/woods/cache/redis_cache_store.rb', line 88

def exist?(key)
  @redis.exists?(key)
rescue ::Redis::BaseError, Errno::ECONNREFUSED, Errno::ECONNRESET => e
  logger.warn("[Woods] RedisCacheStore#exist? failed for #{key}: #{e.message}")
  false
end

#read(key) ⇒ Object?

Read a value from Redis.

Parameters:

  • key (String)

    Cache key

Returns:

  • (Object, nil)

    Deserialized value or nil



40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/woods/cache/redis_cache_store.rb', line 40

def read(key)
  raw = @redis.get(key)
  return nil unless raw

  JSON.parse(raw)
rescue JSON::ParserError
  delete_silently(key)
  nil
rescue ::Redis::BaseError, Errno::ECONNREFUSED, Errno::ECONNRESET => e
  logger.warn("[Woods] RedisCacheStore#read failed for #{key}: #{e.message}")
  nil
end

#write(key, value, ttl: nil) ⇒ void

This method returns an undefined value.

Write a value to Redis with optional TTL.

Parameters:

  • key (String)

    Cache key

  • value (Object)

    Value to cache (must be JSON-serializable)

  • ttl (Integer, nil) (defaults to: nil)

    TTL in seconds (falls back to default_ttl)



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

def write(key, value, ttl: nil)
  serialized = JSON.generate(value)
  effective_ttl = ttl || @default_ttl

  if effective_ttl
    @redis.set(key, serialized, ex: effective_ttl)
  else
    @redis.set(key, serialized)
  end
rescue ::Redis::BaseError, Errno::ECONNREFUSED, Errno::ECONNRESET => e
  logger.warn("[Woods] RedisCacheStore#write failed for #{key}: #{e.message}")
  nil
end