Fix: 3.1.0 llm suggestion raw cache user scoping (#13849)

This commit is contained in:
shamoon authored and GitHub committed 2026-08-29 13:02:05 -07:00
1 parent 7ddc1c9801
commit 9c475e0b27
4 files changed
+168 -24

No files matched your search

+56 -10
View File
@@ -1,7 +1,9 @@
from __future__ import annotations
import hashlib
import logging
import pickle
import uuid
from binascii import hexlify
from collections import OrderedDict
from dataclasses import dataclass
@@ -55,6 +57,8 @@ LLM_CACHE_CLASSIFIER_VERSION: Final[int] = 1001
CACHE_1_MINUTE: Final[int] = 60
CACHE_5_MINUTES: Final[int] = 5 * CACHE_1_MINUTE
CACHE_50_MINUTES: Final[int] = 50 * CACHE_1_MINUTE
# Deliberately longer than any entry it names
LLM_CACHE_GENERATION_TIMEOUT: Final[int] = 2 * CACHE_50_MINUTES
read_cache = caches["read-cache"]
@@ -206,12 +210,40 @@ def refresh_suggestions_cache(
cache.touch(doc_key, timeout)
def invalidate_suggestions_cache(document_id: int) -> None:
"""Invalidate classifier-generated suggestions for a document."""
cache.delete(get_suggestion_cache_key(document_id))
def _llm_generation_key(document_id: int) -> str:
return f"{get_suggestion_cache_key(document_id)}_llm_generation"
def _llm_variant_key(document_id: int, backend: str) -> str:
"""Cache key for one LLM configuration and permission scope.
``backend`` identifies the variant - model, endpoint, output language and
requesting user.
Generating the token on first use lets invalidate_llm_suggestions_cache()
be no-op for documents that never had AI suggestions.
"""
generation_key = _llm_generation_key(document_id)
generation = cache.get_or_set(
generation_key,
lambda: uuid.uuid4().hex,
timeout=LLM_CACHE_GENERATION_TIMEOUT,
)
cache.touch(generation_key, LLM_CACHE_GENERATION_TIMEOUT)
backend_hash = hashlib.sha256(backend.encode()).hexdigest()[:16]
return f"{get_suggestion_cache_key(document_id)}_llm_{generation}_{backend_hash}"
def get_llm_suggestion_cache(
document_id: int,
backend: str,
) -> SuggestionCacheData | None:
doc_key = get_suggestion_cache_key(document_id)
data: SuggestionCacheData = cache.get(doc_key)
data: SuggestionCacheData = cache.get(_llm_variant_key(document_id, backend))
if (
data
@@ -234,9 +266,8 @@ def set_llm_suggestions_cache(
Cache LLM-generated suggestions using a backend-specific identifier
(e.g. 'openai-like:gpt-4').
"""
doc_key = get_suggestion_cache_key(document_id)
cache.set(
doc_key,
_llm_variant_key(document_id, backend),
SuggestionCacheData(
classifier_version=LLM_CACHE_CLASSIFIER_VERSION,
classifier_hash=backend,
@@ -246,17 +277,31 @@ def set_llm_suggestions_cache(
)
def refresh_llm_suggestions_cache(
document_id: int,
backend: str,
*,
timeout: int = CACHE_50_MINUTES,
) -> None:
"""
Refreshes the expiration of one cached LLM suggestion variant.
"""
cache.touch(_llm_variant_key(document_id, backend), timeout)
def invalidate_llm_suggestions_cache(
document_id: int,
) -> None:
"""
Invalidate the LLM suggestions cache for a specific document and backend.
Invalidate every LLM suggestion variant for a document.
"""
doc_key = get_suggestion_cache_key(document_id)
data: SuggestionCacheData = cache.get(doc_key)
if data:
cache.delete(doc_key)
generation_key = _llm_generation_key(document_id)
if cache.get(generation_key) is not None:
cache.set(
generation_key,
uuid.uuid4().hex,
timeout=LLM_CACHE_GENERATION_TIMEOUT,
)
def get_metadata_cache_key(document_id: int) -> str:
@@ -357,3 +402,4 @@ def clear_document_caches(document_id: int) -> None:
get_thumbnail_modified_key(document_id),
],
)
invalidate_llm_suggestions_cache(document_id)