Skip to content

Commit a4f627d

Browse files
committed
refactor(config): Apply better defaults for stale_ttl
1 parent 1ff10c9 commit a4f627d

File tree

7 files changed

+72
-20
lines changed

7 files changed

+72
-20
lines changed

lib/langfuse/client.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def create_memory_cache
166166
PromptCache.new(
167167
ttl: config.cache_ttl,
168168
max_size: config.cache_max_size,
169-
stale_ttl: config.cache_stale_while_revalidate ? config.cache_stale_ttl : nil,
169+
stale_ttl: config.cache_stale_ttl,
170170
refresh_threads: config.cache_refresh_threads,
171171
logger: config.logger
172172
)
@@ -176,7 +176,7 @@ def create_rails_cache_adapter
176176
RailsCacheAdapter.new(
177177
ttl: config.cache_ttl,
178178
lock_timeout: config.cache_lock_timeout,
179-
stale_ttl: config.cache_stale_while_revalidate ? config.cache_stale_ttl : nil,
179+
stale_ttl: config.cache_stale_ttl,
180180
refresh_threads: config.cache_refresh_threads,
181181
logger: config.logger
182182
)

lib/langfuse/config.rb

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ class Config
4646
# @return [Integer] Lock timeout in seconds for distributed cache stampede protection
4747
attr_accessor :cache_lock_timeout
4848

49-
# @return [Boolean] Enable stale-while-revalidate caching
49+
# @return [Boolean] Enable stale-while-revalidate caching (when true, sets cache_stale_ttl to cache_ttl if not customized)
5050
attr_accessor :cache_stale_while_revalidate
5151

52-
# @return [Integer] Stale TTL in seconds (grace period for serving stale data)
52+
# @return [Integer] Stale TTL in seconds (grace period for serving stale data, default: 0 when SWR disabled, cache_ttl when SWR enabled)
5353
attr_accessor :cache_stale_ttl
5454

5555
# @return [Integer] Number of background threads for cache refresh
@@ -95,7 +95,7 @@ def initialize
9595
@cache_backend = DEFAULT_CACHE_BACKEND
9696
@cache_lock_timeout = DEFAULT_CACHE_LOCK_TIMEOUT
9797
@cache_stale_while_revalidate = DEFAULT_CACHE_STALE_WHILE_REVALIDATE
98-
@cache_stale_ttl = @cache_ttl # Default to same as cache_ttl (SWR disabled, entries expire not go stale)
98+
@cache_stale_ttl = 0 # Default to 0 (SWR disabled, entries expire immediately after TTL)
9999
@cache_refresh_threads = DEFAULT_CACHE_REFRESH_THREADS
100100
@tracing_async = DEFAULT_TRACING_ASYNC
101101
@batch_size = DEFAULT_BATCH_SIZE
@@ -104,6 +104,9 @@ def initialize
104104
@logger = default_logger
105105

106106
yield(self) if block_given?
107+
108+
# Apply SWR defaults after yield to allow customization
109+
apply_swr_defaults!
107110
end
108111

109112
# Validate the configuration
@@ -150,11 +153,22 @@ def validate_cache_backend!
150153
end
151154

152155
def validate_swr_config!
153-
raise ConfigurationError, "cache_stale_ttl must be non-negative" if cache_stale_ttl.negative?
156+
if cache_stale_ttl.nil? || cache_stale_ttl.negative?
157+
raise ConfigurationError,
158+
"cache_stale_ttl must be non-negative"
159+
end
154160

155161
return unless cache_refresh_threads.nil? || cache_refresh_threads <= 0
156162

157163
raise ConfigurationError, "cache_refresh_threads must be positive"
158164
end
165+
166+
def apply_swr_defaults!
167+
# When SWR is enabled and stale_ttl hasn't been customized (still 0), default to cache_ttl
168+
return unless cache_stale_while_revalidate
169+
return if cache_stale_ttl != 0 # User has customized it
170+
171+
@cache_stale_ttl = cache_ttl
172+
end
159173
end
160174
end

lib/langfuse/prompt_cache.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ def expired?
5959
#
6060
# @param ttl [Integer] Time-to-live in seconds (default: 60)
6161
# @param max_size [Integer] Maximum cache size (default: 1000)
62-
# @param stale_ttl [Integer, Float::INFINITY, nil] Stale TTL for SWR (default: same as ttl, SWR disabled). Use Float::INFINITY for 1000 years, e.g. non-expiring cache.
62+
# @param stale_ttl [Integer, Float::INFINITY, nil] Stale TTL for SWR (default: 0, SWR disabled). Use Float::INFINITY for 1000 years, e.g. non-expiring cache.
6363
# @param refresh_threads [Integer] Number of background refresh threads (default: 5)
6464
# @param logger [Logger, nil] Logger instance for error reporting (default: nil, creates new logger)
65-
def initialize(ttl: 60, max_size: 1000, stale_ttl: nil, refresh_threads: 5, logger: default_logger)
65+
def initialize(ttl: 60, max_size: 1000, stale_ttl: 0, refresh_threads: 5, logger: default_logger)
6666
@ttl = ttl
6767
@max_size = max_size
68-
@stale_ttl = StaleWhileRevalidate.normalize_stale_ttl(stale_ttl || ttl)
68+
@stale_ttl = StaleWhileRevalidate.normalize_stale_ttl(stale_ttl)
6969
@logger = logger
7070
@cache = {}
7171
@monitor = Monitor.new

lib/langfuse/rails_cache_adapter.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,18 @@ class RailsCacheAdapter
2424
# @param ttl [Integer] Time-to-live in seconds (default: 60)
2525
# @param namespace [String] Cache key namespace (default: "langfuse")
2626
# @param lock_timeout [Integer] Lock timeout in seconds for stampede protection (default: 10)
27-
# @param stale_ttl [Integer, Float::INFINITY, nil] Stale TTL for SWR (default: same as ttl, SWR disabled). Use Float::INFINITY for 1000 years, e.g. non-expiring cache.
27+
# @param stale_ttl [Integer, Float::INFINITY, nil] Stale TTL for SWR (default: 0, SWR disabled). Use Float::INFINITY for 1000 years, e.g. non-expiring cache.
2828
# @param refresh_threads [Integer] Number of background refresh threads (default: 5)
2929
# @param logger [Logger, nil] Logger instance for error reporting (default: nil, creates new logger)
3030
# @raise [ConfigurationError] if Rails.cache is not available
31-
def initialize(ttl: 60, namespace: "langfuse", lock_timeout: 10, stale_ttl: nil, refresh_threads: 5,
31+
def initialize(ttl: 60, namespace: "langfuse", lock_timeout: 10, stale_ttl: 0, refresh_threads: 5,
3232
logger: default_logger)
3333
validate_rails_cache!
3434

3535
@ttl = ttl
3636
@namespace = namespace
3737
@lock_timeout = lock_timeout
38-
@stale_ttl = StaleWhileRevalidate.normalize_stale_ttl(stale_ttl || ttl)
38+
@stale_ttl = StaleWhileRevalidate.normalize_stale_ttl(stale_ttl)
3939
@logger = logger
4040
initialize_swr(refresh_threads: refresh_threads) if @stale_ttl > @ttl
4141
end

spec/langfuse/client_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ class << self
148148
client = described_class.new(config_with_rails_cache)
149149
adapter = client.api_client.cache
150150

151-
# When SWR disabled, stale_ttl defaults to ttl (no stale period, immediate expiration)
152-
expect(adapter.stale_ttl).to eq(120) # Same as cache_ttl
153-
expect(adapter.thread_pool).to be_nil # Thread pool not initialized when stale_ttl == ttl
151+
# When SWR disabled, stale_ttl defaults to 0 (no stale period, immediate expiration)
152+
expect(adapter.stale_ttl).to eq(0)
153+
expect(adapter.thread_pool).to be_nil # Thread pool not initialized when stale_ttl <= ttl
154154
end
155155
end
156156

spec/langfuse/config_spec.rb

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
expect(config.cache_max_size).to eq(1000)
1212
expect(config.cache_backend).to eq(:memory)
1313
expect(config.cache_stale_while_revalidate).to be false
14-
expect(config.cache_stale_ttl).to eq(60) # Defaults to cache_ttl
14+
expect(config.cache_stale_ttl).to eq(0) # Defaults to 0 (SWR disabled)
1515
expect(config.cache_refresh_threads).to eq(5)
1616
end
1717

@@ -232,6 +232,14 @@
232232
)
233233
end
234234

235+
it "raises ConfigurationError when nil" do
236+
config.cache_stale_ttl = nil
237+
expect { config.validate! }.to raise_error(
238+
Langfuse::ConfigurationError,
239+
"cache_stale_ttl must be non-negative"
240+
)
241+
end
242+
235243
it "allows zero" do
236244
config.cache_stale_ttl = 0
237245
expect { config.validate! }.not_to raise_error
@@ -394,9 +402,39 @@
394402
expect { config.validate! }.not_to raise_error
395403

396404
expect(config.cache_stale_while_revalidate).to be false
397-
expect(config.cache_stale_ttl).to eq(60) # Defaults to cache_ttl
405+
expect(config.cache_stale_ttl).to eq(0) # Defaults to 0 (SWR disabled)
398406
expect(config.cache_refresh_threads).to eq(5) # Default
399407
end
408+
409+
it "automatically sets stale_ttl to cache_ttl when SWR is enabled without explicit stale_ttl" do
410+
config = described_class.new do |c|
411+
c.public_key = "pk_test"
412+
c.secret_key = "sk_test"
413+
c.cache_ttl = 120
414+
c.cache_stale_while_revalidate = true
415+
# Not setting cache_stale_ttl explicitly
416+
end
417+
418+
expect { config.validate! }.not_to raise_error
419+
420+
expect(config.cache_stale_while_revalidate).to be true
421+
expect(config.cache_stale_ttl).to eq(120) # Auto-defaults to cache_ttl
422+
end
423+
424+
it "allows customizing stale_ttl when SWR is enabled" do
425+
config = described_class.new do |c|
426+
c.public_key = "pk_test"
427+
c.secret_key = "sk_test"
428+
c.cache_ttl = 60
429+
c.cache_stale_while_revalidate = true
430+
c.cache_stale_ttl = 180 # Custom value
431+
end
432+
433+
expect { config.validate! }.not_to raise_error
434+
435+
expect(config.cache_stale_while_revalidate).to be true
436+
expect(config.cache_stale_ttl).to eq(180) # Respects custom value
437+
end
400438
end
401439

402440
describe "constants" do

spec/langfuse/prompt_cache_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@
8484
expect(cache.stale_ttl).to eq(Langfuse::StaleWhileRevalidate::THOUSAND_YEARS_IN_SECONDS)
8585
end
8686

87-
it "defaults nil to ttl value" do
88-
cache = described_class.new(ttl: 60, stale_ttl: nil)
89-
expect(cache.stale_ttl).to eq(60)
87+
it "defaults to 0 when not specified (SWR disabled)" do
88+
cache = described_class.new(ttl: 60)
89+
expect(cache.stale_ttl).to eq(0)
9090
end
9191
end
9292
end

0 commit comments

Comments
 (0)