Skip to content

Commit 3b5f3aa

Browse files
TomeHirataCopilot
andauthored
Fallback to memory cache when disk is not available (#8718)
* Fallback to memory cache when disk is not available * Update dspy/clients/__init__.py Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent 68fda25 commit 3b5f3aa

File tree

2 files changed

+57
-10
lines changed

2 files changed

+57
-10
lines changed

dspy/clients/__init__.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,47 @@ def configure_cache(
3131
memory_max_entries: The maximum number of entries in the in-memory cache.
3232
"""
3333

34-
import dspy
35-
36-
dspy.cache = Cache(
34+
DSPY_CACHE = Cache(
3735
enable_disk_cache,
3836
enable_memory_cache,
3937
disk_cache_dir,
4038
disk_size_limit_bytes,
4139
memory_max_entries,
4240
)
4341

42+
import dspy
43+
# Update the reference to point to the new cache
44+
dspy.cache = DSPY_CACHE
45+
4446

4547
litellm.telemetry = False
4648
litellm.cache = None # By default we disable LiteLLM cache and use DSPy on-disk cache.
4749

48-
DSPY_CACHE = Cache(
49-
enable_disk_cache=True,
50-
enable_memory_cache=True,
51-
disk_cache_dir=DISK_CACHE_DIR,
52-
disk_size_limit_bytes=DISK_CACHE_LIMIT,
53-
memory_max_entries=1000000,
54-
)
50+
def _get_dspy_cache():
51+
disk_cache_dir = os.environ.get("DSPY_CACHEDIR") or os.path.join(Path.home(), ".dspy_cache")
52+
disk_cache_limit = int(os.environ.get("DSPY_CACHE_LIMIT", 3e10))
53+
54+
try:
55+
_dspy_cache = Cache(
56+
enable_disk_cache=True,
57+
enable_memory_cache=True,
58+
disk_cache_dir=disk_cache_dir,
59+
disk_size_limit_bytes=disk_cache_limit,
60+
memory_max_entries=1000000,
61+
)
62+
except Exception as e:
63+
# If cache creation fails (e.g., in AWS Lambda), create a memory-only cache
64+
logger.warning("Failed to initialize disk cache, falling back to memory-only cache: %s", e)
65+
_dspy_cache = Cache(
66+
enable_disk_cache=False,
67+
enable_memory_cache=True,
68+
disk_cache_dir=disk_cache_dir,
69+
disk_size_limit_bytes=disk_cache_limit,
70+
memory_max_entries=1000000,
71+
)
72+
return _dspy_cache
73+
74+
DSPY_CACHE = _get_dspy_cache()
5575

5676
if "LITELLM_LOCAL_MODEL_COST_MAP" not in os.environ:
5777
# Accessed at run time by litellm; i.e., fine to keep after import

tests/clients/test_cache.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
from dataclasses import dataclass
23
from unittest.mock import patch
34

@@ -317,3 +318,29 @@ def test_function(**kwargs):
317318
)
318319
is not None
319320
)
321+
322+
323+
def test_cache_fallback_on_restricted_environment():
324+
"""Test that DSPy gracefully falls back to memory-only cache when disk cache fails."""
325+
old_env = os.environ.get("DSPY_CACHEDIR")
326+
try:
327+
# Set an invalid cache directory that can't be created
328+
os.environ["DSPY_CACHEDIR"] = "/dev/null/invalid_path"
329+
330+
import dspy
331+
from dspy.clients import _get_dspy_cache
332+
333+
dspy.cache = _get_dspy_cache()
334+
335+
# Cache should work with memory-only fallback despite invalid disk path
336+
test_request = {"model": "test", "prompt": "hello"}
337+
dspy.cache.put(test_request, "fallback_result")
338+
result = dspy.cache.get(test_request)
339+
340+
assert result == "fallback_result", "Memory cache fallback should work"
341+
342+
finally:
343+
if old_env is None:
344+
os.environ.pop("DSPY_CACHEDIR", None)
345+
else:
346+
os.environ["DSPY_CACHEDIR"] = old_env

0 commit comments

Comments
 (0)