Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c514628

Browse files
authored
feat(prompts): optional override for default prompt cache TTL (#1249)
1 parent 651a177 commit c514628

File tree

3 files changed

+196
-2
lines changed

3 files changed

+196
-2
lines changed

‎langfuse/_client/environment_variables.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,13 @@
128128
129129
**Default value**: ``5``
130130
"""
131+
132+
LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS = "LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS"
133+
"""
134+
.. envvar: LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS
135+
136+
Controls the default time-to-live (TTL) in seconds for cached prompts.
137+
This setting determines how long prompt responses are cached before they expire.
138+
139+
**Default value**: ``60``
140+
"""

‎langfuse/_utils/prompt_cache.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
from queue import Empty, Queue
77
from threading import Thread
88
from typing import Callable, Dict, List, Optional, Set
9+
import os
910

1011
from langfuse.model import PromptClient
12+
from langfuse._client.environment_variables import (
13+
LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS
14+
)
1115

12-
DEFAULT_PROMPT_CACHE_TTL_SECONDS = 60
16+
DEFAULT_PROMPT_CACHE_TTL_SECONDS = int(os.getenv(LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS, 60))
1317

1418
DEFAULT_PROMPT_CACHE_REFRESH_WORKERS = 1
1519

‎tests/test_prompt.py‎

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from langfuse.model import ChatPromptClient, TextPromptClient
1414
from tests.utils import create_uuid, get_api
1515

16+
import os
17+
from langfuse._client.environment_variables import LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS
1618

1719
def test_create_prompt():
1820
langfuse = Langfuse()
@@ -688,6 +690,16 @@ def langfuse():
688690

689691
return langfuse_instance
690692

693+
@pytest.fixture
694+
def langfuse_with_override_default_cache():
695+
langfuse_instance = Langfuse(
696+
public_key="test-public-key",
697+
secret_key="test-secret-key",
698+
host="https://mock-host.com",
699+
default_cache_ttl_seconds=OVERRIDE_DEFAULT_PROMPT_CACHE_TTL_SECONDS,
700+
)
701+
langfuse_instance.api = Mock()
702+
return langfuse_instance
691703

692704
# Fetching a new prompt when nothing in cache
693705
def test_get_fresh_prompt(langfuse):
@@ -1416,6 +1428,174 @@ def test_update_prompt():
14161428
assert sorted(updated_prompt.labels) == expected_labels
14171429

14181430

1431+
def test_environment_variable_override_prompt_cache_ttl():
1432+
"""Test that LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS environment variable overrides default TTL."""
1433+
import os
1434+
from unittest.mock import patch
1435+
1436+
# Set environment variable to override default TTL
1437+
os.environ[LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS] = "120"
1438+
1439+
# Create a new Langfuse instance to pick up the environment variable
1440+
langfuse = Langfuse(
1441+
public_key="test-public-key",
1442+
secret_key="test-secret-key",
1443+
host="https://mock-host.com",
1444+
)
1445+
langfuse.api = Mock()
1446+
1447+
prompt_name = "test_env_override_ttl"
1448+
prompt = Prompt_Text(
1449+
name=prompt_name,
1450+
version=1,
1451+
prompt="Test prompt with env override",
1452+
type="text",
1453+
labels=[],
1454+
config={},
1455+
tags=[],
1456+
)
1457+
prompt_client = TextPromptClient(prompt)
1458+
1459+
mock_server_call = langfuse.api.prompts.get
1460+
mock_server_call.return_value = prompt
1461+
1462+
# Mock time to control cache expiration
1463+
with patch.object(PromptCacheItem, "get_epoch_seconds") as mock_time:
1464+
mock_time.return_value = 0
1465+
1466+
# First call - should cache the prompt
1467+
result1 = langfuse.get_prompt(prompt_name)
1468+
assert mock_server_call.call_count == 1
1469+
assert result1 == prompt_client
1470+
1471+
# Check that prompt is cached
1472+
cached_item = langfuse._resources.prompt_cache.get(
1473+
langfuse._resources.prompt_cache.generate_cache_key(prompt_name, version=None, label=None)
1474+
)
1475+
assert cached_item is not None
1476+
assert cached_item.value == prompt_client
1477+
1478+
# Debug: check the cache item's expiry time
1479+
print(f"DEBUG: Cache item expiry: {cached_item._expiry}")
1480+
print(f"DEBUG: Current mock time: {mock_time.return_value}")
1481+
print(f"DEBUG: Is expired? {cached_item.is_expired()}")
1482+
1483+
# Set time to 60 seconds (before new TTL of 120 seconds)
1484+
mock_time.return_value = 60
1485+
1486+
# Second call - should still use cache
1487+
result2 = langfuse.get_prompt(prompt_name)
1488+
assert mock_server_call.call_count == 1 # No new server call
1489+
assert result2 == prompt_client
1490+
1491+
# Set time to 120 seconds (at TTL expiration)
1492+
mock_time.return_value = 120
1493+
1494+
# Third call - should still use cache (stale cache behavior)
1495+
result3 = langfuse.get_prompt(prompt_name)
1496+
assert result3 == prompt_client
1497+
1498+
# Wait for background refresh to complete
1499+
while True:
1500+
if langfuse._resources.prompt_cache._task_manager.active_tasks() == 0:
1501+
break
1502+
sleep(0.1)
1503+
1504+
# Should have made a new server call for refresh
1505+
assert mock_server_call.call_count == 2
1506+
1507+
# Set time to 121 seconds (after TTL expiration)
1508+
mock_time.return_value = 121
1509+
1510+
# Fourth call - should use refreshed cache
1511+
result4 = langfuse.get_prompt(prompt_name)
1512+
assert result4 == prompt_client
1513+
1514+
# Clean up environment variable
1515+
if LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS in os.environ:
1516+
del os.environ[LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS]
1517+
1518+
1519+
@patch.object(PromptCacheItem, "get_epoch_seconds")
1520+
def test_default_ttl_when_environment_variable_not_set(mock_time):
1521+
"""Test that default 60-second TTL is used when LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS is not set."""
1522+
from unittest.mock import patch
1523+
1524+
# Ensure environment variable is not set
1525+
if LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS in os.environ:
1526+
del os.environ[LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS]
1527+
1528+
# Set initial time to 0
1529+
mock_time.return_value = 0
1530+
1531+
# Create a new Langfuse instance to pick up the default TTL
1532+
langfuse = Langfuse(
1533+
public_key="test-public-key",
1534+
secret_key="test-secret-key",
1535+
host="https://mock-host.com",
1536+
)
1537+
langfuse.api = Mock()
1538+
1539+
prompt_name = "test_default_ttl"
1540+
prompt = Prompt_Text(
1541+
name=prompt_name,
1542+
version=1,
1543+
prompt="Test prompt with default TTL",
1544+
type="text",
1545+
labels=[],
1546+
config={},
1547+
tags=[],
1548+
)
1549+
prompt_client = TextPromptClient(prompt)
1550+
1551+
mock_server_call = langfuse.api.prompts.get
1552+
mock_server_call.return_value = prompt
1553+
1554+
# First call - should cache the prompt
1555+
result1 = langfuse.get_prompt(prompt_name)
1556+
assert mock_server_call.call_count == 1
1557+
assert result1 == prompt_client
1558+
1559+
# Check that prompt is cached
1560+
cached_item = langfuse._resources.prompt_cache.get(
1561+
langfuse._resources.prompt_cache.generate_cache_key(prompt_name, version=None, label=None)
1562+
)
1563+
assert cached_item is not None
1564+
assert cached_item.value == prompt_client
1565+
1566+
# Set time to just before default TTL expiration
1567+
mock_time.return_value = DEFAULT_PROMPT_CACHE_TTL_SECONDS - 1
1568+
1569+
# Second call - should still use cache
1570+
result2 = langfuse.get_prompt(prompt_name)
1571+
assert mock_server_call.call_count == 1 # No new server call
1572+
assert result2 == prompt_client
1573+
1574+
# Set time to just after default TTL expiration to trigger cache expiry
1575+
# Use the actual DEFAULT_PROMPT_CACHE_TTL_SECONDS value that was imported
1576+
mock_time.return_value = DEFAULT_PROMPT_CACHE_TTL_SECONDS + 1
1577+
1578+
# Third call - should still use cache (stale cache behavior)
1579+
result3 = langfuse.get_prompt(prompt_name)
1580+
assert result3 == prompt_client
1581+
1582+
# Wait for background refresh to complete
1583+
while True:
1584+
if langfuse._resources.prompt_cache._task_manager.active_tasks() == 0:
1585+
break
1586+
sleep(0.1)
1587+
1588+
# Should have made a new server call for refresh
1589+
assert mock_server_call.call_count == 2
1590+
1591+
# Set time to just after default TTL expiration
1592+
mock_time.return_value = DEFAULT_PROMPT_CACHE_TTL_SECONDS + 1
1593+
1594+
# Fourth call - should use refreshed cache
1595+
result4 = langfuse.get_prompt(prompt_name)
1596+
assert result4 == prompt_client
1597+
1598+
14191599
def test_clear_prompt_cache(langfuse):
14201600
"""Test clearing the entire prompt cache."""
14211601
prompt_name = create_uuid()
@@ -1460,4 +1640,4 @@ def test_clear_prompt_cache(langfuse):
14601640

14611641
# Verify data integrity
14621642
assert prompt_client.name == prompt_name
1463-
assert cached_prompt.name == prompt_name
1643+
assert cached_prompt.name == prompt_name

0 commit comments

Comments
 (0)