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

Uploaded Python 3

File details

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

File metadata

  • Download URL: qx_cache-0.2.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.0

File hashes

Hashes for qx_cache-0.2.0.tar.gz
Algorithm Hash digest
SHA256 96dc9d97bfe0c73096839df7608b87e6b253f7188a19c5cf46478c88a3da8264
MD5 0b9ee1524246c0c976c3536f1bd56c94
BLAKE2b-256 17887cfeba9f7af709287c774037e8fd33d7ebc95c397ffcf3dd98df55367033

See more details on using hashes here.

File details

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

File metadata

  • Download URL: qx_cache-0.2.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.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 be713416e15d88d1de25479622534e31034ba787bf801c5dd585fbdd63e8a60a
MD5 ff397a49ccf043abdf110773f7546659
BLAKE2b-256 b70556f201cbc0da515f2783eb848bbe1b778f1bdf02c7c050c168bd7850e2fb

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