mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
Merge pull request #13933 from michal-otmianowski/ignore-expired-s3-cache-entries
Verify if cache entry has expired prior to serving it to client
This commit is contained in:
commit
22934907ba
2 changed files with 58 additions and 5 deletions
|
|
@ -13,6 +13,7 @@ import asyncio
|
|||
import json
|
||||
from functools import partial
|
||||
from typing import Optional
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
from litellm._logging import print_verbose, verbose_logger
|
||||
|
||||
|
|
@ -69,11 +70,9 @@ class S3Cache(BaseCache):
|
|||
|
||||
if ttl is not None:
|
||||
cache_control = f"immutable, max-age={ttl}, s-maxage={ttl}"
|
||||
import datetime
|
||||
|
||||
# Calculate expiration time
|
||||
expiration_time = datetime.datetime.now() + datetime.timedelta(seconds=ttl)
|
||||
|
||||
expiration_time = datetime.now(timezone.utc) + timedelta(seconds=ttl)
|
||||
# Upload the data to S3 with the calculated expiration time
|
||||
self.s3_client.put_object(
|
||||
Bucket=self.bucket_name,
|
||||
|
|
@ -126,6 +125,13 @@ class S3Cache(BaseCache):
|
|||
)
|
||||
|
||||
if cached_response is not None:
|
||||
if "Expires" in cached_response:
|
||||
expires_time = cached_response['Expires']
|
||||
current_time = datetime.now(expires_time.tzinfo)
|
||||
|
||||
if current_time > expires_time:
|
||||
return None
|
||||
|
||||
# cached_response is in `b{} convert it to ModelResponse
|
||||
cached_response = (
|
||||
cached_response["Body"].read().decode("utf-8")
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ def test_s3_cache_set_cache_with_ttl(mock_s3_dependencies):
|
|||
assert "max-age=3600" in call_args[1]["CacheControl"]
|
||||
|
||||
|
||||
def test_s3_cache_get_cache(mock_s3_dependencies):
|
||||
def test_s3_cache_get_cache_no_expires_info_in_response(mock_s3_dependencies):
|
||||
"""Test basic get_cache functionality"""
|
||||
cache = S3Cache("test-bucket")
|
||||
|
||||
|
|
@ -75,6 +75,54 @@ def test_s3_cache_get_cache(mock_s3_dependencies):
|
|||
|
||||
assert result == {"key": "value", "number": 42}
|
||||
|
||||
def test_s3_cache_get_cache_with_expires_valid(mock_s3_dependencies):
|
||||
"""Test get_cache when response contains Expires and cache entry is still valid"""
|
||||
cache = S3Cache("test-bucket")
|
||||
|
||||
# Create a future expiration time (1 hour from now)
|
||||
future_time = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=1)
|
||||
|
||||
mock_response = {
|
||||
"Body": MagicMock(),
|
||||
"Expires": future_time
|
||||
}
|
||||
mock_response["Body"].read.return_value = b'{"key": "value", "number": 42}'
|
||||
cache.s3_client.get_object.return_value = mock_response
|
||||
|
||||
result = cache.get_cache("test_key")
|
||||
|
||||
cache.s3_client.get_object.assert_called_once_with(
|
||||
Bucket="test-bucket",
|
||||
Key="test_key"
|
||||
)
|
||||
|
||||
# Should return the cached value since it's not expired
|
||||
assert result == {"key": "value", "number": 42}
|
||||
|
||||
|
||||
def test_s3_cache_get_cache_with_expires_expired(mock_s3_dependencies):
|
||||
"""Test get_cache when response contains Expires and cache entry is no longer valid"""
|
||||
cache = S3Cache("test-bucket")
|
||||
|
||||
# Create a past expiration time (1 hour ago)
|
||||
past_time = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)
|
||||
|
||||
mock_response = {
|
||||
"Body": MagicMock(),
|
||||
"Expires": past_time
|
||||
}
|
||||
mock_response["Body"].read.return_value = b'{"key": "value", "number": 42}'
|
||||
cache.s3_client.get_object.return_value = mock_response
|
||||
|
||||
result = cache.get_cache("test_key")
|
||||
|
||||
cache.s3_client.get_object.assert_called_once_with(
|
||||
Bucket="test-bucket",
|
||||
Key="test_key"
|
||||
)
|
||||
|
||||
# Should return None since the cache entry is expired
|
||||
assert result is None
|
||||
|
||||
def test_s3_cache_get_cache_not_found(mock_s3_dependencies):
|
||||
"""Test get_cache when key is not found"""
|
||||
|
|
@ -126,7 +174,6 @@ def test_s3_cache_initialization():
|
|||
cache_with_path = S3Cache("test-bucket", s3_path="my/cache/path")
|
||||
assert cache_with_path.key_prefix == "my/cache/path/"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# ASYNC TESTS
|
||||
# ============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue