cache changes

* add `delete_old`, `clear`, and `close` methods to Cache
* user iterator in `get_keys` and `get_namespace` of RedisCache
This commit is contained in:
Izalia Mae 2024-02-15 21:57:19 -05:00
parent 6f3a1db17d
commit 8c85f23c86

View file

@ -6,7 +6,7 @@ import typing
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import asdict, dataclass from dataclasses import asdict, dataclass
from datetime import datetime, timezone from datetime import datetime, timedelta, timezone
from redis import Redis from redis import Redis
from .database import get_database from .database import get_database
@ -94,6 +94,7 @@ class Cache(ABC):
self.app = app self.app = app
self.setup() self.setup()
@abstractmethod @abstractmethod
def get(self, namespace: str, key: str) -> Item: def get(self, namespace: str, key: str) -> Item:
... ...
@ -119,11 +120,26 @@ class Cache(ABC):
... ...
@abstractmethod
def delete_old(self, days: int = 14) -> None:
...
@abstractmethod
def clear(self) -> None:
...
@abstractmethod @abstractmethod
def setup(self) -> None: def setup(self) -> None:
... ...
@abstractmethod
def close(self) -> None:
...
def set_item(self, item: Item) -> Item: def set_item(self, item: Item) -> Item:
return self.set( return self.set(
item.namespace, item.namespace,
@ -201,12 +217,32 @@ class SqlCache(Cache):
pass pass
def delete_old(self, days: int = 14) -> None:
limit = datetime.now(tz = timezone.utc) - timedelta(days = days)
params = {"limit": limit.timestamp()}
with self._db.connection() as conn:
with conn.execute("DELETE FROM cache WHERE updated < :limit", params):
pass
def clear(self) -> None:
with self._db.connection() as conn:
with conn.execute("DELETE FROM cache"):
pass
def setup(self) -> None: def setup(self) -> None:
with self._db.connection() as conn: with self._db.connection() as conn:
with conn.exec_statement(f'create-cache-table-{self._db.type.name.lower()}', None): with conn.exec_statement(f'create-cache-table-{self._db.type.name.lower()}', None):
pass pass
def close(self) -> None:
self._db.close()
self._db = None
@register_cache @register_cache
class RedisCache(Cache): class RedisCache(Cache):
name: str = 'redis' name: str = 'redis'
@ -239,7 +275,7 @@ class RedisCache(Cache):
def get_keys(self, namespace: str) -> Iterator[str]: def get_keys(self, namespace: str) -> Iterator[str]:
for key in self._rd.keys(self.get_key_name(namespace, '*')): for key in self._rd.scan_iter(self.get_key_name(namespace, '*')):
*_, key_name = key.split(':', 2) *_, key_name = key.split(':', 2)
yield key_name yield key_name
@ -247,7 +283,7 @@ class RedisCache(Cache):
def get_namespaces(self) -> Iterator[str]: def get_namespaces(self) -> Iterator[str]:
namespaces = [] namespaces = []
for key in self._rd.keys(f'{self.prefix}:*'): for key in self._rd.scan_iter(f'{self.prefix}:*'):
_, namespace, _ = key.split(':', 2) _, namespace, _ = key.split(':', 2)
if namespace not in namespaces: if namespace not in namespaces:
@ -269,6 +305,21 @@ class RedisCache(Cache):
self._rd.delete(self.get_key_name(namespace, key)) self._rd.delete(self.get_key_name(namespace, key))
def delete_old(self, days: int = 14) -> None:
limit = datetime.now(tz = timezone.utc) - timedelta(days = days)
for full_key in self._rd.scan_iter(f'{self.prefix}:*'):
_, namespace, key = full_key.split(':', 2)
item = self.get(namespace, key)
if item.updated < limit:
self.delete_item(item)
def clear(self) -> None:
self._rd.delete(f"{self.prefix}:*")
def setup(self) -> None: def setup(self) -> None:
options = { options = {
'client_name': f'ActivityRelay_{self.app.config.domain}', 'client_name': f'ActivityRelay_{self.app.config.domain}',
@ -286,3 +337,8 @@ class RedisCache(Cache):
options['port'] = self.app.config.rd_port options['port'] = self.app.config.rd_port
self._rd = Redis(**options) self._rd = Redis(**options)
def close(self) -> None:
self._rd.close()
self._rd = None