Files
re-xxm/reaction_board/web/cache.py
T

69 lines
2.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""看板聚合结果的内存 TTL 缓存。
缓存键包含数据库路径和数据版本;版本存放在 ``kv``(``cache:v:<group>``),
因此同一个进程内的调度任务和 Web 线程都会看到一致的失效,跨进程的 CLI
导入也可以通过提升版本让旧缓存失效。
"""
from __future__ import annotations
import threading
import time
from typing import Any, Callable, Hashable
TTL_VIDEOS = 3600
TTL_FANS = 86400
class TTLCache:
def __init__(self, *, clock: Callable[[], float] = time.time, max_items: int = 256) -> None:
self._clock = clock
self._max_items = max(16, int(max_items))
self._lock = threading.RLock()
self._items: dict[Hashable, tuple[float, Any]] = {}
def get(self, key: Hashable) -> Any | None:
with self._lock:
entry = self._items.get(key)
if entry is None:
return None
expires_at, value = entry
if expires_at <= self._clock():
self._items.pop(key, None)
return None
return value
def set(self, key: Hashable, ttl: float, value: Any) -> None:
with self._lock:
now = self._clock()
self._items[key] = (now + float(ttl), value)
if len(self._items) > self._max_items:
expired = [k for k, (exp, _) in self._items.items() if exp <= now]
for item in expired:
self._items.pop(item, None)
if len(self._items) > self._max_items:
oldest = sorted(self._items.items(), key=lambda kv: kv[1][0])
for item, _ in oldest[: len(self._items) - self._max_items]:
self._items.pop(item, None)
def clear(self) -> None:
with self._lock:
self._items.clear()
def __len__(self) -> int:
with self._lock:
return len(self._items)
DASHBOARD_CACHE = TTLCache()
def build_cache_key(
scope: str,
group: str,
version: int,
params: dict[str, Any] | None = None,
) -> tuple[Any, ...]:
frozen = tuple(sorted((str(key), str(value)) for key, value in (params or {}).items()))
return (scope, group, int(version), frozen)