From bda4da65c58b537dba01f2279fddededbedc63d2 Mon Sep 17 00:00:00 2001 From: CrazyTodd-one <263771835+CrazyTodd-one@users.noreply.github.com> Date: Fri, 3 Apr 2026 03:57:19 -0400 Subject: [PATCH 1/2] feat: add configurable cache backend (redis/memcache) Fixes #259 --- pyproject.toml | 2 +- src/quartz_api/cmd/main.py | 18 +++++++++++++++++- src/quartz_api/cmd/server.conf | 7 +++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 89e8ff8..02c61d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ "sqlalchemy>=2.0.44", "apitally[fastapi]>=0.22.3", "auth0-fastapi-api>=1.0.0b5", - "fastapi-cache2[memcache]>=0.2.2", + "fastapi-cache2[redis,memcache]>=0.2.2", "slowapi>=0.1.9", "grpc-requests>=0.1.21", "gunicorn>=25.3.0", diff --git a/src/quartz_api/cmd/main.py b/src/quartz_api/cmd/main.py index 5b4b1e7..dc13ec6 100644 --- a/src/quartz_api/cmd/main.py +++ b/src/quartz_api/cmd/main.py @@ -168,7 +168,23 @@ def _create_server(conf: ConfigTree) -> FastAPI: }, ) - FastAPICache.init(InMemoryBackend(), expire=120, prefix="fastapi-cache") + match conf.get_string("cache.backend"): + case "redis": + from fastapi_cache.backends.redis import RedisBackend + from redis import asyncio as aioredis + + redis = aioredis.from_url(conf.get_string("cache.url")) + FastAPICache.init(RedisBackend(redis), expire=120, prefix="fastapi-cache") + case "memcache": + from fastapi_cache.backends.memcached import MemcachedBackend + from aiomcache import Client as MemcachedClient + + host, _, port = conf.get_string("cache.url").rpartition(":") + mc = MemcachedClient(host or "localhost", int(port or 11211)) + FastAPICache.init(MemcachedBackend(mc), expire=120, prefix="fastapi-cache") + case _: + FastAPICache.init(InMemoryBackend(), expire=120, prefix="fastapi-cache") + log.warning("using in-memory cache. NOT recommended for production with multiple workers") # Register rate limiter server.state.limiter = ratelimit.limiter diff --git a/src/quartz_api/cmd/server.conf b/src/quartz_api/cmd/server.conf index 1ff7307..ddf67ac 100644 --- a/src/quartz_api/cmd/server.conf +++ b/src/quartz_api/cmd/server.conf @@ -64,6 +64,13 @@ sentry { cache { refresh_token = "" refresh_token = ${?CACHE_REFRESH_TOKEN} + // Cache backend: "inmemory", "redis", or "memcache" + // Use redis or memcache for production with multiple workers + backend = "inmemory" + backend = ${?CACHE_BACKEND} + // Connection URL for redis (redis://host:6379) or memcache (host:11211) + url = "" + url = ${?CACHE_URL} } // Apitally configuration From ce90f4e2d4d955c272fc28a195f3190d9fbba182 Mon Sep 17 00:00:00 2001 From: CrazyTodd-one <263771835+CrazyTodd-one@users.noreply.github.com> Date: Fri, 3 Apr 2026 04:10:27 -0400 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20lint=20=E2=80=94=20sort=20imports,?= =?UTF-8?q?=20wrap=20long=20line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/quartz_api/cmd/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/quartz_api/cmd/main.py b/src/quartz_api/cmd/main.py index dc13ec6..a999d13 100644 --- a/src/quartz_api/cmd/main.py +++ b/src/quartz_api/cmd/main.py @@ -176,15 +176,18 @@ def _create_server(conf: ConfigTree) -> FastAPI: redis = aioredis.from_url(conf.get_string("cache.url")) FastAPICache.init(RedisBackend(redis), expire=120, prefix="fastapi-cache") case "memcache": - from fastapi_cache.backends.memcached import MemcachedBackend from aiomcache import Client as MemcachedClient + from fastapi_cache.backends.memcached import MemcachedBackend host, _, port = conf.get_string("cache.url").rpartition(":") mc = MemcachedClient(host or "localhost", int(port or 11211)) FastAPICache.init(MemcachedBackend(mc), expire=120, prefix="fastapi-cache") case _: FastAPICache.init(InMemoryBackend(), expire=120, prefix="fastapi-cache") - log.warning("using in-memory cache. NOT recommended for production with multiple workers") + log.warning( + "using in-memory cache. NOT recommended for production" + " with multiple workers", + ) # Register rate limiter server.state.limiter = ratelimit.limiter