From 3b004567dff177df61b412766b1ba0a42c9d623c Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Sat, 8 Mar 2025 11:45:38 +0000 Subject: [PATCH] Implement dogpile cache for Notecolours --- app/models.py | 38 ++++++++++++++++++++++++++++++-------- pyproject.toml | 1 + uv.lock | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/app/models.py b/app/models.py index e3a756b..66f8c73 100644 --- a/app/models.py +++ b/app/models.py @@ -10,6 +10,8 @@ import sys # PyQt imports # Third party imports +from dogpile.cache import make_region +from dogpile.cache.api import NO_VALUE from sqlalchemy import ( bindparam, delete, @@ -40,6 +42,11 @@ if "unittest" in sys.modules and "sqlite" not in DATABASE_URL: raise ValueError("Unit tests running on non-Sqlite database") db = DatabaseManager.get_instance(DATABASE_URL, engine_options=Config.ENGINE_OPTIONS).db +# Configure the cache region +cache_region = make_region().configure( + 'dogpile.cache.memory', # Use in-memory caching for now (switch to Redis if needed) + expiration_time=600 # Cache expires after 10 minutes +) def run_sql(session: Session, sql: str) -> Sequence[RowMapping]: """ @@ -54,6 +61,7 @@ def run_sql(session: Session, sql: str) -> Sequence[RowMapping]: # Database classes class NoteColours(dbtables.NoteColoursTable): + def __init__( self, session: Session, @@ -80,7 +88,22 @@ class NoteColours(dbtables.NoteColoursTable): Return all records """ - result = session.scalars(select(cls)).all() + cache_key = "note_colours_all" + cached_result = cache_region.get(cache_key) + + if cached_result is NO_VALUE: + # Query the database + result = session.scalars( + select(cls) + .where( + cls.enabled.is_(True), + ) + .order_by(cls.order) + ).all() + cache_region.set(cache_key, result) + else: + result = cached_result + return result @staticmethod @@ -97,13 +120,7 @@ class NoteColours(dbtables.NoteColoursTable): return None match = False - for rec in session.scalars( - select(NoteColours) - .where( - NoteColours.enabled.is_(True), - ) - .order_by(NoteColours.order) - ).all(): + for rec in NoteColours.get_all(session): if rec.is_regex: flags = re.UNICODE if not rec.is_casesensitive: @@ -126,6 +143,11 @@ class NoteColours(dbtables.NoteColoursTable): return rec.colour return None + def invalidate_cache(self) -> None: + """Invalidate dogpile cache""" + + cache_region.delete("note_colours_all") + class Playdates(dbtables.PlaydatesTable): def __init__( diff --git a/pyproject.toml b/pyproject.toml index ee189ae..09d7c0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,7 @@ dependencies = [ "pyyaml (>=6.0.2,<7.0.0)", "audioop-lts>=0.2.1", "types-pyyaml>=6.0.12.20241230", + "dogpile-cache>=1.3.4", ] [dependency-groups] diff --git a/uv.lock b/uv.lock index e14e719..b8f3114 100644 --- a/uv.lock +++ b/uv.lock @@ -168,6 +168,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, ] +[[package]] +name = "dogpile-cache" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "decorator" }, + { name = "stevedore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/b7/2fa37f52b4f38bc8eb6d4923163dd822ca6f9e2f817378478a5de73b239e/dogpile_cache-1.3.4.tar.gz", hash = "sha256:4f0295575f5fdd3f7e13c84ba8e36656971d1869a2081b4737ec99ede378a8c0", size = 933234 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/82/d118accb66f9048acbc4ff91592755c24d52f54cce40d6b0b2a0ce351cf5/dogpile.cache-1.3.4-py3-none-any.whl", hash = "sha256:a393412f93d24a8942fdf9248dc80678127d54c5e60a7be404027aa193cafe12", size = 62859 }, +] + [[package]] name = "entrypoints" version = "0.4" @@ -449,6 +462,7 @@ dependencies = [ { name = "alembic" }, { name = "audioop-lts" }, { name = "colorlog" }, + { name = "dogpile-cache" }, { name = "fuzzywuzzy" }, { name = "mutagen" }, { name = "mysqlclient" }, @@ -492,6 +506,7 @@ requires-dist = [ { name = "alembic", specifier = ">=1.14.0" }, { name = "audioop-lts", specifier = ">=0.2.1" }, { name = "colorlog", specifier = ">=6.9.0" }, + { name = "dogpile-cache", specifier = ">=1.3.4" }, { name = "fuzzywuzzy", specifier = ">=0.18.0" }, { name = "mutagen", specifier = ">=1.47.0" }, { name = "mysqlclient", specifier = ">=2.2.5" }, @@ -641,6 +656,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, ] +[[package]] +name = "pbr" +version = "6.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/d2/510cc0d218e753ba62a1bc1434651db3cd797a9716a0a66cc714cb4f0935/pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b", size = 125702 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/ac/684d71315abc7b1214d59304e23a982472967f6bf4bde5a98f1503f648dc/pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76", size = 108997 }, +] + [[package]] name = "pexpect" version = "4.9.0" @@ -1028,6 +1055,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, ] +[[package]] +name = "setuptools" +version = "75.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", size = 1344083 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", size = 1229385 }, +] + [[package]] name = "sqlalchemy" version = "2.0.38" @@ -1072,6 +1108,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/15/485186e37a06d28b7fc9020ad57ba1e3778ee9e8930ff6c9ea350946ffe1/stackprinter-0.2.12-py3-none-any.whl", hash = "sha256:0a0623d46a5babd7a8a9787f605f4dd4a42d6ff7aee140541d5e9291a506e8d9", size = 29282 }, ] +[[package]] +name = "stevedore" +version = "5.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pbr" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/3f/13cacea96900bbd31bb05c6b74135f85d15564fc583802be56976c940470/stevedore-5.4.1.tar.gz", hash = "sha256:3135b5ae50fe12816ef291baff420acb727fcd356106e3e9cbfa9e5985cd6f4b", size = 513858 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/45/8c4ebc0c460e6ec38e62ab245ad3c7fc10b210116cea7c16d61602aa9558/stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe", size = 49533 }, +] + [[package]] name = "text-unidecode" version = "1.3"