From 48f25488df2a48ea91b2f20adae89e34a336f802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 28 Aug 2023 11:56:59 +0200 Subject: [PATCH] [CHORE] cleanup cache and exception on `make test` (#1899) * [CHORE] cleanup cache and exception on `make test` moved the invalidate_forever task to proper location and use `create_permanent_task`. and there was a Task never awaited Exception when running tests * imrpove expiration test * move cache into utils * fix issue with pytest_asyncio s --------- Co-authored-by: jacksn --- lnbits/app.py | 5 ++--- lnbits/{ => utils}/cache.py | 7 ++++--- lnbits/utils/exchange_rates.py | 2 +- tests/core/test_cache.py | 28 +++++++++++++++++----------- 4 files changed, 24 insertions(+), 18 deletions(-) rename lnbits/{ => utils}/cache.py (90%) diff --git a/lnbits/app.py b/lnbits/app.py index 96b3f483f..657fa13bb 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -20,7 +20,6 @@ from slowapi import Limiter from slowapi.util import get_remote_address from starlette.responses import JSONResponse -from lnbits.cache import cache from lnbits.core.crud import get_installed_extensions from lnbits.core.helpers import migrate_extension_database from lnbits.core.services import websocketUpdater @@ -30,6 +29,7 @@ from lnbits.core.tasks import ( # register_watchdog,; unregister_watchdog, ) from lnbits.settings import settings from lnbits.tasks import cancel_all_tasks, create_permanent_task +from lnbits.utils.cache import cache from lnbits.wallets import get_wallet_class, set_wallet_class from .commands import db_versions, load_disabled_extension_list, migrate_databases @@ -358,8 +358,6 @@ def register_startup(app: FastAPI): if settings.lnbits_admin_ui: initialize_server_logger() - asyncio.create_task(cache.invalidate_forever()) - except Exception as e: logger.error(str(e)) raise ImportError("Failed to run 'startup' event.") @@ -431,6 +429,7 @@ def register_async_tasks(app): create_permanent_task(check_pending_payments) create_permanent_task(invoice_listener) create_permanent_task(internal_invoice_listener) + create_permanent_task(cache.invalidate_forever) register_task_listeners() register_killswitch() # await run_deferred_async() # calle: doesn't do anyting? diff --git a/lnbits/cache.py b/lnbits/utils/cache.py similarity index 90% rename from lnbits/cache.py rename to lnbits/utils/cache.py index 41955bdd9..a5f54958c 100644 --- a/lnbits/cache.py +++ b/lnbits/utils/cache.py @@ -17,7 +17,8 @@ class Cache: Small caching utility providing simple get/set interface (very much like redis) """ - def __init__(self) -> None: + def __init__(self, interval: float = 10) -> None: + self.interval = interval self._values: dict[Any, Cached] = {} def get(self, key: str, default=None) -> Optional[Any]: @@ -50,10 +51,10 @@ class Cache: self.set(key, value, expiry=expiry) return value - async def invalidate_forever(self, interval: float = 10): + async def invalidate_forever(self): while True: try: - await asyncio.sleep(interval) + await asyncio.sleep(self.interval) ts = time() expired = [k for k, v in self._values.items() if v.expiry < ts] for k in expired: diff --git a/lnbits/utils/exchange_rates.py b/lnbits/utils/exchange_rates.py index 52b1d4ac9..89567535d 100644 --- a/lnbits/utils/exchange_rates.py +++ b/lnbits/utils/exchange_rates.py @@ -4,7 +4,7 @@ from typing import Callable, NamedTuple import httpx from loguru import logger -from lnbits.cache import cache +from lnbits.utils.cache import cache currencies = { "AED": "United Arab Emirates Dirham", diff --git a/tests/core/test_cache.py b/tests/core/test_cache.py index 9e3e93527..4191f6e30 100644 --- a/tests/core/test_cache.py +++ b/tests/core/test_cache.py @@ -2,23 +2,22 @@ import asyncio import pytest -from lnbits.cache import Cache +from lnbits.utils.cache import Cache from tests.conftest import pytest_asyncio - -@pytest_asyncio.fixture(scope="session") -async def cache(): - cache = Cache() - - task = asyncio.create_task(cache.invalidate_forever(interval=0.1)) - yield cache - task.cancel() - - key = "foo" value = "bar" +@pytest_asyncio.fixture +async def cache(): + cache = Cache(interval=0.1) + + task = asyncio.create_task(cache.invalidate_forever()) + yield cache + task.cancel() + + @pytest.mark.asyncio async def test_cache_get_set(cache): cache.set(key, value) @@ -29,8 +28,15 @@ async def test_cache_get_set(cache): @pytest.mark.asyncio async def test_cache_expiry(cache): + # gets expired by `get` call + cache.set(key, value, expiry=0.01) + await asyncio.sleep(0.02) + assert not cache.get(key) + + # gets expired by invalidation task cache.set(key, value, expiry=0.1) await asyncio.sleep(0.2) + assert key not in cache._values assert not cache.get(key)