Repository navigation
feat(backend): enhance distributed concurrency control and locking for Idempotency Key Manager - #1607
Open
Abidoyesimze wants to merge 1 commit into
Conversation
…r Idempotency Key Manager
Replaces the check-then-set idempotency flow (GET followed by a
fire-and-forget SET) with a distributed lock built on an atomic
SET NX PX acquisition keyed per merchant+key:
- Concurrent duplicates now receive 409 while the original request is
still in flight instead of both executing (the previous race let every
duplicate through).
- Completion is written with two Lua compare-and-swap scripts so a
worker that lost its lock (TTL expiry or crash) can never clobber the
state of the request that re-acquired the key; orphaned completions
are counted and logged instead.
- Non-2xx responses release the lock immediately so clients can retry,
and connections that close before a response release it too.
- Replays now return the original status code (legacy 201 fallback) and
set Idempotency-Replayed; legacy {"hash","response"} records are still
honoured so the change is backwards compatible.
- Redis failures still fail open but are now logged and counted.
Adds Prometheus instrumentation (idempotency_requests_total,
idempotency_lock_duration_seconds, idempotency_orphaned_completions_total)
and unit coverage for the race, lock TTL self-healing, payload mismatch,
legacy replay, fail-open and lock cleanup paths.
|
@Abidoyesimze is attempting to deploy a commit to the Emmanuel's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Abidoyesimze Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1465
src/lib/idempotency.jspreviously used a naive GET-then-SET check with no locking: concurrent requests with the same key could both miss the cache and both execute the handler (duplicate writes), and a crashed in-flight request left a key claimed forever with no recovery path.Rewrites the middleware around a Redis atomic lock:
SET NX PXacquires a per-key lock before the handler runs, with a short TTL and a lock token so only the owner can release it.COMPLETE_LOCK_SCRIPT) — a slow or killed request cannot overwrite a completed result, and a completed result cannot be clobbered by a re-acquired lock.RELEASE_LOCK_SCRIPTreleases the lock with a token check (no unlock-by-accident).409 ConflictwithRetry-Afterinstead of duplicate execution.Idempotency-Replayed: trueheader; request-body hashes must match or the request is rejected.New metrics (in the main registry,
backend/src/lib/metrics.js):idempotency_requests_total{outcome=completed|replayed|conflict|error}idempotency_lock_duration_secondshistogramidempotency_orphaned_completions_total(Lua CAS mismatches — a signal of crashed holders or clock skew)Test plan
15 of those are new idempotency unit tests: happy path, replay (same body → replayed; different body → mismatch), 409 on in-flight conflict, lock TTL expiry and re-acquisition, token-checked release, Lua CAS mismatch counting, legacy-record replay, Redis-error fail-open, and metric emission.
Full backend suite: no new failures vs.
origin/main(177 pre-existing failures on main, identical count on this branch — mostly network-dependent oracle/horizon tests).Security notes