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

Uploaded Python 3

File details

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

File metadata

  • Download URL: qx_cache-1.1.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.1.0.tar.gz
Algorithm Hash digest
SHA256 0189bead001de290b860a64deca46de698b6189386f93ef57f0e1b988f4d684b
MD5 a89064bc2a2032505917180f147215af
BLAKE2b-256 543fdd0389d703cda5d4e4b380e996bf20f3d071403fdac82686f82b99b726a0

See more details on using hashes here.

File details

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

File metadata

  • Download URL: qx_cache-1.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-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9486791ca377d8a029bbb1106b9095a4e6ffa2cf8df07a9f6ee5a6ee4ac79bd1
MD5 c49cb00f72f2d17783b5afc9fa4a6a83
BLAKE2b-256 5164808c8c89f99fd57880663c6f378109150651ee6634d1e1ae4f0cd49b1b1b

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