[perf] Extension list cache (#3616)

This commit is contained in:
Vlad Stan 2025-12-04 10:57:17 +02:00 committed by GitHub
parent ca94909aab
commit ad268516a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 45 additions and 2 deletions

View file

@ -6,6 +6,7 @@ import json
import os
import shutil
import zipfile
from asyncio.tasks import create_task
from pathlib import Path
from typing import Any
@ -20,6 +21,7 @@ from lnbits.helpers import (
version_parse,
)
from lnbits.settings import settings
from lnbits.utils.cache import cache
class ExplicitRelease(BaseModel):
@ -606,6 +608,37 @@ class InstallableExtension(BaseModel):
@classmethod
async def get_installable_extensions(
cls, post_refresh_cache: bool = False
) -> list[InstallableExtension]:
extension_list: list[InstallableExtension] = []
cache_key = "extensions:installable"
cache_value = cache.value(cache_key)
if not cache_value:
extension_list = await cls._get_installable_extensions()
cache.set(cache_key, extension_list, expiry=3600) # one hour
return extension_list
if cache_value.older_than(10 * 60) or post_refresh_cache:
# refresh cache in background if older than 10 minutes or requested
create_task(cls._refresh_installable_extensions_cache())
extension_list = cache_value.value # type: ignore
return extension_list
@classmethod
async def _refresh_installable_extensions_cache(
cls,
) -> None:
cache_key = "extensions:installable"
extension_list: list[InstallableExtension] = (
await cls._get_installable_extensions()
)
cache.set(cache_key, extension_list, expiry=3600)
@classmethod
async def _get_installable_extensions(
cls,
) -> list[InstallableExtension]:
extension_list: list[InstallableExtension] = []

View file

@ -57,7 +57,9 @@ async def run_by_the_minute_tasks() -> None:
if minute_counter % 60 == 0:
try:
# initialize the list of all extensions
await InstallableExtension.get_installable_extensions()
await InstallableExtension.get_installable_extensions(
post_refresh_cache=True
)
except Exception as ex:
logger.error(ex)

View file

@ -508,7 +508,9 @@ async def extensions(account_id: AccountId = Depends(check_account_id_exists)):
installed_exts: list[InstallableExtension] = await get_installed_extensions()
installed_exts_ids = [e.id for e in installed_exts]
installable_exts = await InstallableExtension.get_installable_extensions()
installable_exts = await InstallableExtension.get_installable_extensions(
post_refresh_cache=account_id.is_admin_id
)
installable_exts_ids = [e.id for e in installable_exts]
installable_exts += [e for e in installed_exts if e.id not in installable_exts_ids]

View file

@ -13,6 +13,9 @@ class Cached(NamedTuple):
value: Any
expiry: float
def older_than(self, seconds: float) -> bool:
return time() - self.expiry > seconds
class Cache:
"""
@ -23,6 +26,9 @@ class Cache:
self.interval = interval
self._values: dict[Any, Cached] = {}
def value(self, key: str) -> Cached | None:
return self._values.get(key)
def get(self, key: str, default=None) -> Any | None:
cached = self._values.get(key)
if cached is not None: