Releases: vilyam/gcp-pubsub-idempotency
Releases · vilyam/gcp-pubsub-idempotency
Release list
v0.1.0
Initial public release.
Added
lock(key, *, backend, lease, on_duplicate=None)— the core context manager. Runs the
withbody at most once for a key: a duplicate raisesDuplicateon enter (body skipped),
a live holder raisesInProgress, a body exception releases the key for retry, and success
records the key DONE. Ownership is a monotonic fencing token:complete()commits on a
fence match even after the lease lapsed (an unreclaimed lapsed holder is still the only
party that ran the work), andrelease()advances the fence so a released claim can never
be completed afterwards.mutex(key, *, backend, lease)— the serialize-without-deduplicating sibling, built on the
same backend port. Alwaysrelease()s and nevercomplete()s, so a mutex key is never
DONE: distinct messages for one entity (e.g. successive status updates for one purchase
order) each run, one at a time, none dropped. Mutual exclusion, not ordering.@idempotent(backend=..., key=..., lease=...)— the pub/sub layer: wraps a
functions_framework CloudEvent handler and maps the outcome to ack/nack (duplicate → ack,
contention → quiet 503 with a warning log carrying the message'sdeliveryAttempt, work
error → 500). Key defaults to the Pub/SubmessageId; override withkey=. Accepts a
backend instance, a zero-arg factory, or a backend class (built lazily, once). Fails closed
on unkeyed messages unlessallow_unguarded=True; rejects async handlers at decoration
and at runtime.on_duplicateobservation hook (DuplicateHook) onlock()and@idempotent— called
with the key when a delivery is a duplicate; best-effort and payload-agnostic, it never
changes the outcome.- Lock backends implementing the
LockBackendport:InMemoryLock,DatastoreLock
(production default; serializable transactions, claim-token retry re-affirmation),
RedisLock(single-key Lua CAS, server-side clock, cluster-safe),SqlLock(any DB-API
2.0 driver, epoch-ms timestamps,FOR UPDATE+ PK tiebreak, deadlock-code retries). Each
owns itsttlwith lazy read-time expiry — no cron, no background sweeper. message_id()anddelivery_attempt()routers resolving the id and the dead-letter
attempt counter across push, Eventarc CloudEvent, raw push body and streaming-pull shapes —
envelope metadata only, never payload.GCP_PUBSUB_IDEMPOTENCY_DISABLEDenv switch:@idempotentbecomes a warning pass-through
(backend never built) for unit-testing handler bodies.- Backend contract suite run against every backend (memory / SQLite / PostgreSQL / Redis /
Datastore emulator, auto-started in Docker), a docker-compose end-to-end harness (real
Pub/Sub + Datastore emulators, real push subscriptions, multi-instance crash storm), Redis
server-clock tests, and a@idempotent+functions_framework integration test. examples/(Cloud Function, Cloud Run, local dev),COMPARISON.md(alternatives & prior
art),DECISIONS.md, and CI/release workflows (PyPI Trusted Publishing).