Files
wehub-resource-sync c889a57b6b
Test Suites / Build CI Environment (push) Has been cancelled
Test Suites / Basic Tests (push) Has been cancelled
Test Suites / End-to-End Tests (push) Has been cancelled
Test Suites / CLI Tests (push) Has been cancelled
Test Suites / Slow End-to-End Tests (push) Has been cancelled
Test Suites / Graph Database Tests (push) Has been cancelled
Test Suites / Vector DB Tests (push) Has been cancelled
Test Suites / Temporal Graph Test (push) Has been cancelled
Test Suites / Search Test on Different DBs (push) Has been cancelled
Test Suites / Example Tests (push) Has been cancelled
Test Suites / Notebook Tests (push) Has been cancelled
Test Suites / OS and Python Tests Ubuntu (push) Has been cancelled
Test Suites / OS and Python Tests Extended (push) Has been cancelled
Test Suites / LLM Test Suite (push) Has been cancelled
Test Suites / S3 File Storage Test (push) Has been cancelled
Test Suites / Run Integration Tests (push) Has been cancelled
Test Suites / MCP Tests (push) Has been cancelled
Test Suites / Docker Compose Test (push) Has been cancelled
Test Suites / Docker CI test (push) Has been cancelled
Test Suites / Relational DB Migration Tests (push) Has been cancelled
Test Suites / Distributed Cognee Test (push) Has been cancelled
Test Suites / DB Examples Tests (push) Has been cancelled
Test Suites / Test Completion Status (push) Has been cancelled
Test Suites / Claude Code Review (push) Has been cancelled
Test Suites / basic checks (push) Has been cancelled
build | Build and Push Cognee MCP Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
build | Build and Push Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.11) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.12) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (kuzu, kuzu) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (neo4j, neo4j) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Examples (push) Has been cancelled
Weighted Edges Tests / Code Quality for Weighted Edges (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:02:24 +08:00

215 lines
8.2 KiB
Python

"""Factory to get the appropriate cache coordination engine (e.g., Redis)."""
import os
from functools import lru_cache
from typing import Optional
from cognee.shared.logging_utils import get_logger
from cognee.infrastructure.databases.cache.config import get_cache_config
from cognee.infrastructure.databases.cache.cache_db_interface import CacheDBInterface
from cognee.infrastructure.databases.cache.fscache.FsCacheAdapter import FSCacheAdapter
from cognee.infrastructure.databases.exceptions import CacheConnectionError
logger = get_logger("CacheEngine")
def _resolve_cache_db_url(backend: str, cache_db_url: Optional[str]) -> str:
"""
Resolve the SQLAlchemy async URL for the SQL cache backends.
CACHE_DB_URL wins when set. Otherwise "sqlite" mirrors the relational SQLite
engine's databases directory (with a dedicated cache.db file), and "postgres"
falls back to the relational DB_* settings when DB_PROVIDER=postgres.
"""
if cache_db_url:
return cache_db_url
from cognee.infrastructure.databases.relational.config import get_relational_config
relational_config = get_relational_config()
if backend == "sqlite":
db_path = relational_config.db_path
if "s3://" in db_path:
raise CacheConnectionError(
"CACHE_BACKEND=sqlite cannot store cache.db on S3; "
"set CACHE_DB_URL or CACHE_BACKEND=postgres"
)
os.makedirs(db_path, exist_ok=True)
return f"sqlite+aiosqlite:///{db_path}/cache.db"
if relational_config.db_provider == "postgres":
from sqlalchemy import URL
logger.warning(
"CACHE_BACKEND=postgres without CACHE_DB_URL; "
"falling back to the relational DB_* settings."
)
return URL.create(
"postgresql+asyncpg",
username=relational_config.db_username,
password=relational_config.db_password,
host=relational_config.db_host,
port=int(relational_config.db_port),
database=relational_config.db_name,
).render_as_string(hide_password=False)
raise CacheConnectionError(
"CACHE_BACKEND=postgres requires CACHE_DB_URL or DB_PROVIDER=postgres"
)
@lru_cache
def create_cache_engine(
cache_host: str,
cache_port: int,
cache_username: str,
cache_password: str,
lock_key: str,
log_key: str,
agentic_lock_expire: int = 240,
agentic_lock_timeout: int = 300,
session_ttl_seconds: int | None = 604800,
tapes_ingest_url: str = "http://localhost:8082",
tapes_provider: str = "openai",
tapes_agent_name: str = "cognee",
tapes_model: str = "cognee-session",
tapes_request_timeout: float = 5.0,
cache_db_url: str | None = None,
cache_purge_interval_seconds: int = 900,
):
"""
Factory function to instantiate a cache coordination backend.
Parameters:
-----------
- cache_host: Hostname or IP of the cache server.
- cache_port: Port number to connect to.
- cache_username: Username to authenticate with.
- cache_password: Password to authenticate with.
- lock_key: Identifier used for the locking resource.
- log_key: Identifier used for usage logging.
- agentic_lock_expire: Duration to hold the lock after acquisition.
- agentic_lock_timeout: Max time to wait for the lock before failing.
- cache_db_url: SQLAlchemy async URL for the SQL cache backends.
- cache_purge_interval_seconds: Minimum interval between global TTL purge sweeps.
Returns:
--------
- CacheDBInterface: An instance of the appropriate cache adapter.
"""
config = get_cache_config()
if config.caching or config.usage_logging:
if config.cache_backend == "redis":
from cognee.infrastructure.databases.cache.redis.RedisAdapter import RedisAdapter
return RedisAdapter(
host=cache_host,
port=cache_port,
username=cache_username,
password=cache_password,
lock_name=lock_key,
log_key=log_key,
timeout=agentic_lock_expire,
blocking_timeout=agentic_lock_timeout,
session_ttl_seconds=session_ttl_seconds,
)
elif config.cache_backend == "fs":
return FSCacheAdapter(session_ttl_seconds=session_ttl_seconds)
elif config.cache_backend == "tapes":
from cognee.infrastructure.databases.cache.tapes.TapesCacheAdapter import (
TapesCacheAdapter,
)
return TapesCacheAdapter(
session_ttl_seconds=session_ttl_seconds,
tapes_ingest_url=tapes_ingest_url,
tapes_provider=tapes_provider,
tapes_agent_name=tapes_agent_name,
tapes_model=tapes_model,
tapes_request_timeout=tapes_request_timeout,
)
elif config.cache_backend in ("sqlite", "postgres"):
from cognee.infrastructure.databases.cache.sql.SqlCacheAdapter import (
SqlCacheAdapter,
)
try:
connection_string = _resolve_cache_db_url(config.cache_backend, cache_db_url)
except CacheConnectionError as error:
# An explicitly chosen backend must fail loudly. The implicit
# sqlite default, however, can land on deployments it cannot
# serve (e.g. system root on S3) - degrade to the filesystem
# cache there so sessions keep working out of the box.
explicitly_chosen = "cache_backend" in getattr(config, "model_fields_set", set())
if config.cache_backend != "sqlite" or explicitly_chosen:
raise
logger.warning(
f"Default sqlite cache backend is unavailable ({error}); "
"falling back to the filesystem cache backend. "
"Set CACHE_DB_URL or CACHE_BACKEND to override."
)
return FSCacheAdapter(session_ttl_seconds=session_ttl_seconds)
return SqlCacheAdapter(
connection_string=connection_string,
lock_key=lock_key,
log_key=log_key,
session_ttl_seconds=session_ttl_seconds,
agentic_lock_expire=agentic_lock_expire,
agentic_lock_timeout=agentic_lock_timeout,
purge_interval_seconds=cache_purge_interval_seconds,
)
else:
raise ValueError(
f"Unsupported cache backend: '{config.cache_backend}'. "
f"Supported backends are: 'redis', 'fs', 'tapes', 'sqlite', 'postgres'"
)
else:
return None
def get_cache_engine(
lock_key: Optional[str] = "default_lock",
log_key: Optional[str] = "usage_logs",
) -> Optional[CacheDBInterface]:
"""
Returns a cache adapter instance using current context configuration.
"""
config = get_cache_config()
return create_cache_engine(
cache_host=config.cache_host,
cache_port=config.cache_port,
cache_username=config.cache_username,
cache_password=config.cache_password,
lock_key=lock_key,
log_key=log_key,
agentic_lock_expire=config.agentic_lock_expire,
agentic_lock_timeout=config.agentic_lock_timeout,
session_ttl_seconds=config.session_ttl_seconds,
tapes_ingest_url=config.tapes_ingest_url,
tapes_provider=config.tapes_provider,
tapes_agent_name=config.tapes_agent_name,
tapes_model=config.tapes_model,
tapes_request_timeout=config.tapes_request_timeout,
cache_db_url=config.cache_db_url,
cache_purge_interval_seconds=config.cache_purge_interval_seconds,
)
async def close_cache_engine(
lock_key: Optional[str] = "default_lock",
log_key: Optional[str] = "usage_logs",
) -> None:
"""Close and clear the cached cache engine instance."""
if create_cache_engine.cache_info().currsize == 0:
return
try:
cache_engine = get_cache_engine(lock_key=lock_key, log_key=log_key)
if cache_engine is not None:
await cache_engine.close()
finally:
create_cache_engine.cache_clear()