Skip to main content

omnixys-cache

Omnixys shared cache package — a typed Redis/Valkey facade with JSON serialization, invalidation, distributed locks, rate limiting, streams with consumer groups, and delayed jobs, all on one client.

Installation

pip install omnixys-cache

Features

  • CacheClient: async Redis/Valkey facade with typed keys, JSON serialization, TTL handling, atomic NX/PX ops and low-level raw access
  • Key definitions: create_key(prefix, ttl_seconds) and key(...) builders validated at construction time
  • CacheLock: distributed mutual-exclusion lock with token-based (WATCH/MULTI) release
  • RateLimiter: fixed-window rate limiting with hit/check and TTL window reset
  • ValkeyStreamService: stream + consumer-group queues (ensureGroup, enqueue, consume, read_pending, ack)
  • Delayed jobs: schedule/claim/retry/cancel delayed jobs with a worker loop and decorator-driven registry
  • Invalidation: CacheInvalidationService with pluggable strategies
  • Serialization: JSON serializers (JsonCacheSerializer, StrictJsonCacheSerializer)
  • DI: CacheProvider container integration (dishka)

Usage

Client and keys

import asyncio
from cache import CacheClient, create_key

session = create_key("session", ttl_seconds=300)
cache = CacheClient(url="redis://localhost:6379", key_prefix="myapp")

async def main() -> None:
    await cache.set_json(session, {"userId": 42}, parts=("u1",))  # myapp:session:u1
    assert await cache.get_json(session, "u1") == {"userId": 42}
    await cache.expire(session, 60, "u1")
    await cache.close()

asyncio.run(main())

Raw keys work too — pass a plain str and optional parts are joined with :.

Distributed lock

from cache import CacheClient, CacheLock

async with CacheLock(cache, "deploy:eu1", ttl_ms=30_000, wait_ms=10_000) as lock:
    ...
# or manually:
lock = CacheLock(cache, "deploy:eu1", ttl_ms=30_000)
if await lock.acquire():
    try:
        ...
    finally:
        await lock.release()

Rate limiting

from cache import CacheClient, RateLimiter

limiter = RateLimiter(cache)
if not await limiter.check("sms:user:42", limit=5, ttl_seconds=60).allowed:
    raise RuntimeError("rate limit exceeded")

Streams with consumer groups

from cache import CacheClient, ValkeyStreamService

streams = ValkeyStreamService(cache)
await streams.ensure_group("jobs", "workers")

await streams.enqueue("jobs", {"type": "resize", "imageId": "abc"})

for message in await streams.consume("jobs", "workers", consumer="w1", block_ms=1_000):
    payload = message.data          # {"type": "resize", "imageId": "abc"}
    await streams.ack("jobs", "workers", message.id)

Delayed jobs

from cache import DelayedJobService, DelayedJobSchedule, DelayedJobWorker, delayed_job

@delayed_job("image.resize")
async def resize(payload: dict) -> None:
    print(payload["imageId"])

service = DelayedJobService(cache)
job_id = await service.schedule(
    DelayedJobSchedule(type="image.resize", payload={"imageId": "abc"}, delay_ms=5_000)
)

worker = DelayedJobWorker(service)          # uses the default (decorated) registry
await worker.start()

Jobs are persisted as records (7-day TTL), scheduled on a sorted set (delayed:jobs), claimed atomically via WATCH/MULTI, retried on failure up to max_retries, and surfaced through status(), cancel(), retry(), and claim_due().

Testing

The package ships behavior-level tests (pytest + fakeredis, no server needed):

uv run pytest -q          # 47 tests
uv run ruff check .       # lint
uv run mypy src/          # strict typing

License

GPL-3.0-or-later

Metadata

Release files for omnixys-cache 5.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for omnixys-cache 5.0.0
File Size Uploaded
omnixys_cache-5.0.0.tar.gz 46.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for omnixys-cache 5.0.0
File Interpreter ABI Platform
omnixys_cache-5.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 60.4 kB

Release files / omnixys_cache-5.0.0.tar.gz

Download URL omnixys_cache-5.0.0.tar.gz
Size 46.3 kB
Tags Source
SHA-256 checksum
How to use checksums
07af742a448bbd4a40bf6eb135eb3bb79c23da19ee5e9b4f69258ed8f738a577
BLAKE2b-256 checksum
How to use checksums
f3d8c3facaa37900b618565bf160f5c23bc6a0762a99b7563d05093d660ea80d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.8 {"installer":{"name":"uv","version":"0.12.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / omnixys_cache-5.0.0-py3-none-any.whl

Download URL omnixys_cache-5.0.0-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7a51503018c401b548ad7a59712542698349a9ae8a5e403e3459de58b7123331
BLAKE2b-256 checksum
How to use checksums
5e3d6c777eb0d625510019e80309fbeab17e090aacc67545b0bf5c6daff735f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.8 {"installer":{"name":"uv","version":"0.12.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

5.0.0 This release

2 release files

3.0.7

2 release files

3.0.6

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page