Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Atomic Locks Middleware Laravel Package

pyaesoneaung/atomic-locks-middleware

Laravel middleware that prevents overlapping requests by wrapping routes in atomic cache locks. Guard critical endpoints from concurrent execution with configurable keys, wait times, and automatic release—no boilerplate needed.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Build vs. buy for request serialization. The package is a thin, ~dozen-line convenience wrapper around Laravel's native Cache::lock() / LockProvider primitives. Treat it as a buy only in the sense of "spend zero engineering days"; the real decision is whether to vendor a 34-star dependency or copy the middleware into app/Http/Middleware and own it. For most teams the honest answer is build-in-house, and this package's value is as a reference implementation and a conversation starter.
  • Feature: safe handling of non-idempotent operations. Concretely, it enables or de-risks: duplicate payment/refund submissions from double-clicks or retried requests, webhook handlers that must not run concurrently (Stripe, GitHub, shipping carriers), one-at-a-time admin actions ("recalculate invoices", "sync catalog", "rotate keys"), coupon/inventory decrement race conditions, and report/export generation that would otherwise exhaust workers.
  • Roadmap enabler for "scheduled work without a queue." Teams running cron-driven artisan commands or scheduled HTTP endpoints get withoutOverlapping() semantics for routes, not just jobs. This supports a phased roadmap where the queue infrastructure arrives later; it lets you ship a correct-but-simple version now.
  • Scope boundary against queue middleware. It positions cleanly next to WithoutOverlapping job middleware and Laravel's RateLimiter: the decision matrix is "is this a route or a job?" and "do we want to reject concurrent requests (429/423) or queue them?" The package's answer is reject-or-wait at the HTTP layer, which is a real product behaviour choice (user sees "already in progress" vs. a spinner for 30s).
  • Operational posture / incident prevention. It is a cheap guardrail against thundering-herd self-inflicted outages — e.g. a public "refresh data" endpoint being hit by a retry storm. That is a reliability decision, not a feature decision, and belongs in the roadmap as hardening work.
  • Explicitly not a fit for: distributed transactions, cross-service coordination (locks are per-cache-store, not per-system), or anything needing exactly-once semantics. It reduces a race window; it does not provide idempotency, audit trails, or compensation logic. Those remain separate roadmap items.

When to Consider This Package

Adopt or copy when all of the following hold:

  • You have a specific, named concurrency hazard on an HTTP route: duplicate form submissions, overlapping webhook deliveries, or a "run this now" admin/cron endpoint. If you cannot name the race, you do not need the lock.
  • You are already on a cache store that implements Laravel's LockProvider — Redis, Memcached, database, or DynamoDB. file and array locks are effectively process-local and will not protect you across multiple app servers; if your production cache is file, stop here.
  • Your application is single-region / single cache cluster, or you accept that a lock is scoped to one store. Multi-region active-active is out of scope.
  • You want zero new infrastructure and zero new abstractions — the middleware composes with existing route groups and needs no migration, config file, or service provider work beyond registration.
  • You are comfortable with the maintenance profile: one maintainer, 34 stars, zero dependents, MIT, latest release May 2025. That is a copy-and-own signal, not a depend-and-forget signal. Pin the version, or vendor the file.
  • Timeouts and failure modes are specified up front. Decide explicitly: does a second request block (block()) or fail fast? How long until the lock expires (must exceed worst-case request duration)? What status code and body does the caller get? Does the lock release on exception (it must — finally, not just success)? Unanswered, this package turns a race condition into a 500 storm or a deadlock after a crashed worker.

Look elsewhere when:

  • The work is genuinely queue-shaped — use jobs with WithoutOverlapping and ->onOneServer(). That gives retries, backoff, and observability for free; a route lock gives you none of that.
  • You need rate limiting rather than mutual exclusion — use Laravel's RateLimiter/throttle middleware. Locks are binary; they do not degrade gracefully under load.
  • You need idempotency keys, exactly-once processing, or durable state across failures. A cache lock is advisory and evaporates with the cache; it is not a substitute for a unique constraint, an outbox, or payment-provider idempotency tokens.
  • Your cache store is shared with volatile data that may be flushed under memory pressure (e.g. an eviction policy on Redis). Evicting a lock key silently releases the lock. Use a dedicated store/connection for locks.
  • You require SLA-backed support, security review, or active maintenance. A 34-star, single-maintainer package should not sit on a payment path without an internal owner and a test.

How to Pitch It (Stakeholders)

For executives (30 seconds): We have a handful of endpoints where two requests arriving at the same time corrupt state or double-charge a customer — retried webhooks, double-clicked buttons, a "sync now" button anyone in ops can press. This package is a small, MIT-licensed helper that lets us mark a route "one at a time" using the cache we already pay for. It is not a platform investment; it is a few lines of code we could write ourselves in an afternoon. Recommendation: do not add it as a long-term dependency — copy the ~30-line middleware into our own codebase, add tests, and treat it as internal hardening work. Expected cost: half a day. Expected benefit: eliminates a class of duplicate-action incidents and removes a blocker on shipping the webhook and admin-tools roadmap items.

For engineering (the real pitch): Laravel already ships atomic locks — Cache::lock(), the Lock object, withoutOverlapping() for jobs. The gap is the HTTP layer, where we currently hand-roll Cache::lock(...)->get() boilerplate in controllers, inconsistently, and usually without a finally release. This package is that middleware, done correctly and small enough to read in one sitting. Use it as the shape of the solution, then own it:

  • One middleware, applied per-route or per-group (->middleware('atomic-lock:invoice-recalc')).
  • Named lock key + explicit TTL longer than the worst-case request.
  • Block-with-timeout or fail-fast with a documented 409/423 and a "this is already running" response the frontend can render.
  • Release in finally; never rely on TTL expiry as the release path.
  • Requires Redis/Memcached/database — not the file driver — and a store we do not let other features evict.

Guardrails we should hold ourselves to: locks are not idempotency and not a substitute for a DB unique constraint. For anything with retries or fan-out, we use a queued job with WithoutOverlapping()->onOneServer() instead. And every locked route gets a test that fires two concurrent requests and asserts exactly one executes — otherwise we have a lock nobody has verified, which is worse than no lock because it buys false confidence.

Risk summary to acknowledge out loud: 34 stars, 0 dependents, single maintainer, last release May 2025. That is fine for a pattern reference and unacceptable for a hidden critical dependency on a payment path. Hence: vendor the code, assign an owner, document the TTL and failure semantics in the runbook, and revisit if the queue migration lands — at which point most of these call sites should become jobs.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource