Source code for loom.core.cache.abc.config
from __future__ import annotations
from typing import Any
import msgspec
[docs]
class CacheConfig(msgspec.Struct, kw_only=True):
"""Configuration for cache behaviour including TTLs and aiocache backend settings.
Attributes:
enabled: Global toggle for cache operations.
aiocache_alias: Named alias for the aiocache data backend. The data
backend **must** be configured with
:class:`~loom.core.cache.serializer.MsgspecSerializer`.
counter_alias: Named alias for the counter backend used by
:class:`~loom.core.cache.dependency.GenerationalDependencyResolver`.
This backend must have **no serializer** so that native atomic
increment operations (Redis ``INCR``, ``SimpleMemoryCache.increment``)
work correctly. Defaults to ``None``, meaning the same alias as
``aiocache_alias`` is used (safe for single-process deployments; uses a
non-atomic GET+SET fallback automatically).
aiocache_config: Raw configuration mapping forwarded to ``aiocache``.
Keyed by alias name. Use :meth:`apply_config
<loom.core.cache.CacheGateway.apply_config>` to have ``max_size``
injected automatically for memory backends.
default_ttl: Default TTL in seconds for single-entity lookups.
default_list_ttl: Default TTL in seconds for list / index queries.
ttl: Per-entity TTL overrides keyed by entity name. Append ``_list``
for list overrides (e.g. ``{"user": 300, "user_list": 150}``).
max_size: Maximum number of entries for ``aiocache.SimpleMemoryCache``
backends. Injected automatically when calling
:meth:`~loom.core.cache.CacheGateway.apply_config`.
Has no effect on Redis or other non-memory backends.
Example YAML (Redis + separate counter backend)::
cache:
aiocache_alias: cache
counter_alias: counters
default_ttl: 300
default_list_ttl: 120
max_size: 1000
ttl:
user: 600
user_list: 300
aiocache:
cache:
cache: aiocache.RedisCache
endpoint: ${oc.env:REDIS_HOST,redis}
port: 6379
namespace: myapp
serializer:
class: loom.core.cache.serializer.MsgspecSerializer
counters:
cache: aiocache.RedisCache
endpoint: ${oc.env:REDIS_HOST,redis}
port: 6379
namespace: myapp_counters
# no serializer — raw integer storage, atomic Redis INCR
Example YAML (in-memory for development)::
cache:
aiocache_alias: cache
counter_alias: counters
max_size: 500
aiocache:
cache:
cache: aiocache.SimpleMemoryCache
serializer:
class: loom.core.cache.serializer.MsgspecSerializer
counters:
cache: aiocache.SimpleMemoryCache
# no serializer
"""
enabled: bool = True
aiocache_alias: str = "default"
counter_alias: str | None = None
aiocache_config: dict[str, Any] = msgspec.field(default_factory=dict)
default_ttl: int = 200
default_list_ttl: int = 120
ttl: dict[str, int] = msgspec.field(default_factory=dict)
max_size: int | None = None
@property
def effective_counter_alias(self) -> str:
"""Return the resolved counter alias, falling back to ``aiocache_alias``."""
return self.counter_alias or self.aiocache_alias
[docs]
@classmethod
def from_mapping(cls, data: dict[str, Any]) -> CacheConfig:
"""Create a ``CacheConfig`` from a raw dictionary (e.g. parsed TOML/YAML).
Args:
data: Flat or nested mapping with cache configuration values.
Returns:
A validated ``CacheConfig`` instance.
"""
raw_counter_alias = data.get("counter_alias")
raw_max_size = data.get("max_size")
return cls(
enabled=bool(data.get("enabled", True)),
aiocache_alias=str(data.get("aiocache_alias", "default")),
counter_alias=str(raw_counter_alias) if raw_counter_alias is not None else None,
aiocache_config=dict(data.get("aiocache", {})),
default_ttl=int(data.get("default_ttl", 200)),
default_list_ttl=int(data.get("default_list_ttl", 120)),
ttl={str(k): int(v) for k, v in dict(data.get("ttl", {})).items()},
max_size=int(raw_max_size) if raw_max_size is not None else None,
)
[docs]
def ttl_for_single(self, entity: str) -> int:
"""Resolve the effective TTL for a single-entity lookup.
Args:
entity: Normalized entity name (e.g. ``"user"``).
Returns:
TTL value in seconds.
"""
return self.ttl.get(entity, self.default_ttl)
[docs]
def ttl_for_list(self, entity: str) -> int:
"""Resolve the effective TTL for a list or index query.
Args:
entity: Normalized entity name (e.g. ``"user"``).
Returns:
TTL value in seconds.
"""
return self.ttl.get(f"{entity}_list", self.default_list_ttl)