Skip to main content

Qx cache layer: Redis client, idempotency store, distributed locks

Project description

qx-cache

Redis client, Lua-atomic idempotency store, and distributed lock for the Qx framework.

What lives here

  • qx.cache.Cache — thin async Redis client wrapper with typed get/set/delete/exists methods and TTL support.
  • qx.cache.CacheSettings — Pydantic settings for Redis connection URL.
  • qx.cache.create_client — async factory that opens and validates a Redis connection.
  • qx.cache.IdempotencyStore — Lua-script-based atomic check-and-set. A single round-trip to Redis either claims an idempotency key (first caller wins) or returns the cached result (all subsequent callers). Used by IdempotencyBehavior in the Mediator pipeline to make command handlers idempotent.
  • qx.cache.DistributedLock — Redis-backed advisory lock with TTL and async context-manager interface. Uses SET NX PX for acquisition and Lua for safe release (only the holder can release).
  • qx.cache.LockNotHeldError — raised when attempting to release a lock that has expired or was never acquired.

Usage

Idempotency store

from qx.cache import IdempotencyStore, create_client

redis = await create_client(settings.cache.url)
store = IdempotencyStore(redis, ttl_seconds=3600)

# In a command handler or pipeline behavior:
key = f"create-order:{cmd.idempotency_key}"
cached = await store.get(key)
if cached is not None:
    return Result.success(cached)

result = await do_work(cmd)
if result.is_success:
    await store.set(key, result.value)
return result

Distributed lock

from qx.cache import DistributedLock

async with DistributedLock(redis, "outbox-relay-leader", ttl_seconds=30):
    await relay.run_once()

Design rules

  • Lua atomicityIdempotencyStore uses a single Lua script for the check-and-set so there is no window between checking and setting, even under concurrent requests.
  • No silent failuresDistributedLock raises LockNotHeldError if the lock has expired before you release it, so callers know their critical section may have overlapped.
  • The cache layer has no dependency on qx-db or qx-cqrs. It can be used standalone.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qx_cache-0.1.0.tar.gz (6.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qx_cache-0.1.0-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

Details for the file qx_cache-0.1.0.tar.gz.

File metadata

  • Download URL: qx_cache-0.1.0.tar.gz
  • Upload date:
  • Size: 6.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for qx_cache-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4a43a97a10603d21b63dc070e47938d25daa10852b790ae79f81041367749af3
MD5 c53a20b719a168fe4c2b2ad1ceafe66d
BLAKE2b-256 0de892ed293a4767d22dad7c4a4b108efc4603aae74d41e7705e3a777fe8261a

See more details on using hashes here.

File details

Details for the file qx_cache-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: qx_cache-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 7.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qx_cache-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 46e259ab88731da72941add48c8b5cd7793e906b6d1db6c3fe6f7d96c1c04ede
MD5 00df490c9ec6b4919a6bb2e7635e710e
BLAKE2b-256 a5fa298fb7db04facd4bc9b8ae388dc7536632009341546e83462c0156305bb9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page