Add minimum to ItemCounter and refactor redis client init

This commit is contained in:
ErikKalkoken
2023-08-02 15:41:47 +02:00
parent 12383d79c8
commit 1f55fbfccc
4 changed files with 124 additions and 71 deletions

View File

@@ -1,21 +1,62 @@
"""Helpers for Task Statistics."""
import logging
from typing import Optional
from app_utils.allianceauth import get_redis_client
from redis import Redis, RedisError
from django.core.cache import cache
logger = logging.getLogger(__name__)
class _RedisStub:
"""Stub of a Redis client.
It's purpose is to prevent EventSeries objects from trying to access Redis
when it is not available. e.g. when the Sphinx docs are rendered by readthedocs.org.
"""
IS_STUB = True
def delete(self, *args, **kwargs):
pass
def incr(self, *args, **kwargs):
return 0
def zadd(self, *args, **kwargs):
pass
def zcount(self, *args, **kwargs):
pass
def zrangebyscore(self, *args, **kwargs):
pass
class ItemCounter:
"""A process safe item counter."""
"""A process safe item counter.
Args:
- name: Unique name for the counter
- minimum: Counter can not go below the minimum, when set
- redis: A Redis client. Will use AA's cache client by default
"""
CACHE_KEY_BASE = "allianceauth-item-counter"
DEFAULT_CACHE_TIMEOUT = 24 * 3600
def __init__(self, name: str) -> None:
def __init__(
self, name: str, minimum: Optional[int] = None, redis: Optional[Redis] = None
) -> None:
if not name:
raise ValueError("Must define a name")
self._name = str(name)
self._minimum = minimum
self._redis = redis if redis else get_redis_client()
@property
def _cache_key(self) -> str:
@@ -23,6 +64,9 @@ class ItemCounter:
def reset(self, init_value: int = 0):
"""Reset counter to initial value."""
if self._minimum is not None and init_value < self._minimum:
raise ValueError("Can not reset below minimum")
cache.set(self._cache_key, init_value, self.DEFAULT_CACHE_TIMEOUT)
def incr(self, delta: int = 1):
@@ -34,6 +78,8 @@ class ItemCounter:
def decr(self, delta: int = 1):
"""Decrement counter by delta."""
if self._minimum is not None and self.value() == self._minimum:
return
try:
cache.decr(self._cache_key, delta)
except ValueError:
@@ -42,3 +88,18 @@ class ItemCounter:
def value(self) -> Optional[int]:
"""Return current value or None if not yet initialized."""
return cache.get(self._cache_key)
def get_redis_client_or_stub():
"""Return AA's default cache client or a stub if Redis is not available."""
redis = get_redis_client()
try:
if not redis.ping():
raise RuntimeError()
except (AttributeError, RedisError, RuntimeError):
logger.exception(
"Failed to establish a connection with Redis. "
"This EventSeries object is disabled.",
)
return _RedisStub()
return redis