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-1.0.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-1.0.0-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for qx_cache-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f0dd1aeffb7e4ff24ca4fd541177664004cd37167ed09991c4e226762e5b3fca
MD5 7d74760b722b07eda840dfb04a18fe14
BLAKE2b-256 224c279385ee0b8df55f63df2dfd0e4bb6bccd0b31b8d9945be58faaa1433e0e

See more details on using hashes here.

File details

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

File metadata

  • Download URL: qx_cache-1.0.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-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3afc39b25df31d13bf8c143f5e356d47a9a09996ad31581c62bf8ce8871267a8
MD5 a6e38c4c4152861b06acfb1ae6f7785a
BLAKE2b-256 1048b4870b5aef685ebf5d505079aea7a0c6576bde74e85dbec2c7e6ca72405e

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