Class: Langfuse::RailsCacheAdapter
- Inherits:
-
Object
- Object
- Langfuse::RailsCacheAdapter
- Includes:
- StaleWhileRevalidate
- Defined in:
- lib/langfuse/rails_cache_adapter.rb
Overview
Rails.cache adapter for distributed caching with Redis
Wraps Rails.cache to provide distributed caching for prompts across multiple processes and servers. Requires Rails with Redis cache store.
Instance Attribute Summary collapse
-
#lock_timeout ⇒ Object
readonly
Returns the value of attribute lock_timeout.
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#namespace ⇒ Object
readonly
Returns the value of attribute namespace.
-
#stale_ttl ⇒ Object
readonly
Returns the value of attribute stale_ttl.
-
#thread_pool ⇒ Object
readonly
Returns the value of attribute thread_pool.
-
#ttl ⇒ Object
readonly
Returns the value of attribute ttl.
Class Method Summary collapse
-
.build_key(name, version: nil, label: nil) ⇒ String
Build a cache key from prompt name and options.
Instance Method Summary collapse
-
#clear ⇒ void
Clear the entire Langfuse cache namespace.
-
#empty? ⇒ Boolean
Check if cache is empty.
-
#fetch_with_lock(key) { ... } ⇒ Object
Fetch a value from cache with lock for stampede protection.
-
#get(key) ⇒ Object?
Get a value from the cache.
-
#initialize(ttl: 60, namespace: "langfuse", lock_timeout: 10, stale_ttl: 0, refresh_threads: 5, logger: default_logger) ⇒ RailsCacheAdapter
constructor
Initialize a new Rails.cache adapter.
-
#set(key, value) ⇒ Object
Set a value in the cache.
-
#size ⇒ nil
Get current cache size.
Methods included from StaleWhileRevalidate
#fetch_with_stale_while_revalidate, #initialize_swr, #shutdown, #swr_enabled?
Constructor Details
#initialize(ttl: 60, namespace: "langfuse", lock_timeout: 10, stale_ttl: 0, refresh_threads: 5, logger: default_logger) ⇒ RailsCacheAdapter
Initialize a new Rails.cache adapter
32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 32 def initialize(ttl: 60, namespace: "langfuse", lock_timeout: 10, stale_ttl: 0, refresh_threads: 5, logger: default_logger) validate_rails_cache! @ttl = ttl @namespace = namespace @lock_timeout = lock_timeout @stale_ttl = stale_ttl @logger = logger initialize_swr(refresh_threads: refresh_threads) if swr_enabled? end |
Instance Attribute Details
#lock_timeout ⇒ Object (readonly)
Returns the value of attribute lock_timeout.
20 21 22 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 20 def lock_timeout @lock_timeout end |
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
20 21 22 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 20 def logger @logger end |
#namespace ⇒ Object (readonly)
Returns the value of attribute namespace.
20 21 22 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 20 def namespace @namespace end |
#stale_ttl ⇒ Object (readonly)
Returns the value of attribute stale_ttl.
20 21 22 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 20 def stale_ttl @stale_ttl end |
#thread_pool ⇒ Object (readonly)
Returns the value of attribute thread_pool.
20 21 22 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 20 def thread_pool @thread_pool end |
#ttl ⇒ Object (readonly)
Returns the value of attribute ttl.
20 21 22 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 20 def ttl @ttl end |
Class Method Details
.build_key(name, version: nil, label: nil) ⇒ String
Build a cache key from prompt name and options
101 102 103 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 101 def self.build_key(name, version: nil, label: nil) PromptCache.build_key(name, version: version, label: label) end |
Instance Method Details
#clear ⇒ void
This method returns an undefined value.
Clear the entire Langfuse cache namespace
Note: This uses delete_matched which may not be available on all cache stores. Works with Redis, Memcached, and memory stores. File store support varies.
70 71 72 73 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 70 def clear # Delete all keys matching the namespace pattern Rails.cache.delete_matched("#{namespace}:*") end |
#empty? ⇒ Boolean
Check if cache is empty
Note: Rails.cache doesn’t provide an efficient way to check if empty, so we return false to indicate this operation is not supported.
91 92 93 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 91 def empty? false end |
#fetch_with_lock(key) { ... } ⇒ Object
Fetch a value from cache with lock for stampede protection
This method prevents cache stampedes (thundering herd) by ensuring only one process/thread fetches from the source when the cache is empty. Others wait for the first one to populate the cache.
Uses exponential backoff: 50ms, 100ms, 200ms (3 retries max, ~350ms total). If cache is still empty after waiting, falls back to fetching from source.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 122 def fetch_with_lock(key) # 1. Check cache first (fast path - no lock needed) cached = get(key) return cached if cached # 2. Cache miss - try to acquire lock lock_key = build_lock_key(key) if acquire_lock(lock_key) begin # We got the lock - fetch from source and populate cache value = yield set(key, value) value ensure # Always release lock, even if block raises release_lock(lock_key) end else # Someone else has the lock - wait for them to populate cache cached = wait_for_cache(key) return cached if cached # Cache still empty after waiting - fall back to fetching ourselves # (This handles cases where lock holder crashed or took too long) yield end end |
#get(key) ⇒ Object?
Get a value from the cache
48 49 50 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 48 def get(key) Rails.cache.read(namespaced_key(key)) end |
#set(key, value) ⇒ Object
Set a value in the cache
57 58 59 60 61 62 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 57 def set(key, value) # Calculate expiration: use total_ttl if SWR enabled, otherwise just ttl expires_in = swr_enabled? ? total_ttl : ttl Rails.cache.write(namespaced_key(key), value, expires_in:) value end |
#size ⇒ nil
Get current cache size
Note: Rails.cache doesn’t provide a size method, so we return nil to indicate this operation is not supported.
81 82 83 |
# File 'lib/langfuse/rails_cache_adapter.rb', line 81 def size nil end |