A Redis-based cache that routes writes to the primary and reads from replicas with failover.
Project description
Kompress Cache
Redis-based cache that routes write operations to a primary Redis instance and read operations to replicas, with automatic failover to the primary in case of replica failure. This package is designed to work seamlessly with FastAPI, making it ideal for modern python web applications.
🔧 Features
- ✅ Async Redis support with graceful error handling
- ✅ Automatic failover from replica to primary
- ✅ Schema validation for cached values using Pydantic
- ✅ Custom cache miss loading via
Loadableinterface - ✅ Support for primary and multiple replicas
- ✅ Configurable via environment variables
⚙️ Configuration options - Environment variables
| Environment Variable | Description | Default Value | Comments | Since |
|---|---|---|---|---|
| REDIS_HOST | Hostname/ IP Address of the Primary Redis cache | localhost |
0.1.0 | |
| REDIS_PORT | Port of the Primary Redis cache | 6379 |
0.1.0 | |
| REDIS_REPLICAS_HOST_PORT | Comma separated redis replicas host port | Example: localhost:6380,localhost:6381 If no replicas provided, the primary redis server will be used for both read and write operations. | 0.1.0 | |
| REDIS_TIMEOUT | Timeout for a redis command execution in seconds | 5 | 0.1.0 |
💡 Usage
- Ensure that all configurations are setup and the given redis servers are running.
kompress_cachelogger need to be configured. For more verbose logs, set the logger level to DEBUG.
🔹 Basic Usage (No Validation)
import json
from kompress_cache import get_cache
cache = get_cache()
user = {"id": "1", "name": "Alice"}
# Set data in Redis (uses the primary Redis instance)
await cache.hset("users", user["id"], json.dumps(user)) # Output: 1
user_id = "1"
# Retrieve data from one of the replicas; fails over to primary if needed
user_cache = await cache.hget("users", user_id) # Output: '{"id": "1", "name": "Alice"}'
if user_cache is None:
print("User cache not found. Fetching from DB...")
user_data = get_user_data_from_db(user_id)
else:
user_data = json.loads(user_cache)
print(user_data)
🚨 Exception Handling
Redis connection issues are automatically caught and converted to appropriate FastAPI HTTPException errors:
| Redis Error | HTTP Status Code | Message |
|---|---|---|
ConnectionError |
503 | Service Unavailable |
TimeoutError |
504 | Gateway Timeout |
Other Redis Exception |
500 | Internal Server Error |
This means you can focus on your logic and let the cache gracefully degrade:
from fastapi import FastAPI, HTTPException
from kompress_cache import get_cache, Loadable
from myapp.models import UserModel
from myapp.db import get_user_data_from_db
app = FastAPI()
cache = get_cache()
@app.get("/users/{user_id}")
async def get_user(user_id: str):
try:
user_loader = MyUserLoader(user_id)
return await cache.hget_l("users", user_id, user_loader, UserModel)
except HTTPException as e:
if e.status_code in (503, 504):
return await get_user_data_from_db(user_id)
raise
🔸 Smart Caching with Pydantic + Loader
Let's take it further using the power of Pydantic and cache-miss loaders.
from pydantic import BaseModel
from kompress_cache import get_cache, Loadable
cache = get_cache()
# Define your Pydantic model
class UserModel(BaseModel):
id: str
name: str
# Create a loader for cache misses
class UserLoader(Loadable):
def __init__(self, user_id: str):
self.user_id = user_id
async def load(self) -> str:
user_data = await get_user_data_from_db_or_external_api(self.user_id)
return UserModel(**user_data).model_dump_json()
user_id = "1"
user_loader = UserLoader(user_id)
# Retrieve the user data
user_data = await cache.hget_l("users", user_id, user_loader, UserModel)
# If data is:
# - not in cache → it is loaded via the loader and cached.
# - in cache → the data is validated against the given BaseModel and if data is:
# - invalid → it is refreshed via the loader.
# - valid → returned as a validated model instance.
print(user_data.id) # "1"
print(user_data.name) # "Alice"
🔁 Evolving Schema with Automatic Refresh
Imagine you update your user schema to include an age field:
class UserModel(BaseModel):
id: str
name: str
age: int
-
If the cache still has the old schema (without age), validation will fail.
-
The hget_l method will detect this, trigger the loader, and update the cache with the latest schema.
✅ No need to manually invalidate the cache — just update your model!
🧪 Built for Async
Your cache logic works natively with async functions. Whether using FastAPI background tasks or high-throughput endpoints, Redis calls are non-blocking, thanks to redis.asyncio.
🤝 Contributing
Pull requests are welcome! For major changes, please open an issue first to discuss what you’d like to change.
📜 License
Authors and acknowledgment
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kompress_cache-0.1.2.tar.gz.
File metadata
- Download URL: kompress_cache-0.1.2.tar.gz
- Upload date:
- Size: 8.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d337c7a87a41c5d48cbac7a26ef0f2fee9658368e21890002eeb2007abefd7ba
|
|
| MD5 |
ec4d855b738cf532c8761d7a3d28c967
|
|
| BLAKE2b-256 |
e8fd98a55e204e7c2a7290ff0400f868823677ac50052f51ffbba93fb7a2036c
|
Provenance
The following attestation bundles were made for kompress_cache-0.1.2.tar.gz:
Publisher:
python-publish.yml on utvyakta-public/kompress-cache
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kompress_cache-0.1.2.tar.gz -
Subject digest:
d337c7a87a41c5d48cbac7a26ef0f2fee9658368e21890002eeb2007abefd7ba - Sigstore transparency entry: 251549925
- Sigstore integration time:
-
Permalink:
utvyakta-public/kompress-cache@75dfb7c0b994527e7cb3e27d9c25c5b919a162ff -
Branch / Tag:
refs/tags/0.0.1 - Owner: https://github.com/utvyakta-public
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@75dfb7c0b994527e7cb3e27d9c25c5b919a162ff -
Trigger Event:
release
-
Statement type:
File details
Details for the file kompress_cache-0.1.2-py3-none-any.whl.
File metadata
- Download URL: kompress_cache-0.1.2-py3-none-any.whl
- Upload date:
- Size: 9.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6bdab4acafde891977cf956ae702bfe20024711415e446b91045c5c9312ca057
|
|
| MD5 |
194093a70eaf556f2e4e1b880bf6b014
|
|
| BLAKE2b-256 |
675bbc2721f136dc3d6eae7215480894c41c0b44ae2565e96eedbb103fcdf92a
|
Provenance
The following attestation bundles were made for kompress_cache-0.1.2-py3-none-any.whl:
Publisher:
python-publish.yml on utvyakta-public/kompress-cache
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kompress_cache-0.1.2-py3-none-any.whl -
Subject digest:
6bdab4acafde891977cf956ae702bfe20024711415e446b91045c5c9312ca057 - Sigstore transparency entry: 251549929
- Sigstore integration time:
-
Permalink:
utvyakta-public/kompress-cache@75dfb7c0b994527e7cb3e27d9c25c5b919a162ff -
Branch / Tag:
refs/tags/0.0.1 - Owner: https://github.com/utvyakta-public
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@75dfb7c0b994527e7cb3e27d9c25c5b919a162ff -
Trigger Event:
release
-
Statement type: