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

Laravel Lock Laravel Package

zaber-dev/laravel-lock

Application-level distributed locking for Laravel with entity-scoped locks, automatic owner detection, and cleanup. Use cache or database storage, attach locks to Eloquent models, and protect routes with middleware to prevent race conditions.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

Feature-level decisions

  • Duplicate side-effect prevention (payments, refunds, payouts, provisioning). This package gives you a per-entity mutex keyed on something meaningful (Lock::for('billing_charge', $user)), which is the missing primitive behind most "user got charged twice" incidents.
  • Serializing stateful workflows: inventory allocation, checkout pipelines, balance transfers, document editing, webhook fan-in. Decide where the serialization point lives — in the job, in the endpoint, or in the model — and this package supports all three without inventing a shared convention per team.
  • Route-level protection as a policy decision, not code: ->middleware('lock:billing_charge,30') lets you declare concurrency policy in the routing table, with automatic 429 and finally-based release. This makes "this endpoint is single-flight per user" reviewable in a diff rather than buried in a controller.
  • Idempotency vs. mutual exclusion: a real product decision. Idempotency keys let work run twice safely; locks prevent the second run. This package makes the locking option cheap enough to choose deliberately for a specific endpoint instead of defaulting to "retry and hope."
  • Single-instance cron/scheduled jobs: a low-cost way to avoid duplicated nightly jobs once you scale past one worker — a decision that otherwise tends to get deferred until it causes an incident.
  • Observability as a product surface: typed LockAcquired/LockReleased/LockFailed events let you alert on contention. That's how you find out a lock is over-broad before it becomes a throughput problem, and it converts "should we invest in concurrency work?" into a data question.

Roadmap decisions

  • Build vs. buy: you are choosing between (a) Cache::lock() plus ~100–300 lines of internal glue in every service that needs it, (b) this package, (c) a dedicated distributed-lock service (Redis/etcd/ZooKeeper with fencing). This package is the "buy" option for teams that want the ergonomics without operating new infrastructure.
  • Adoption depth: cache driver = fast, ephemeral, best-effort (good for bursty endpoints); database driver = persistent, queryable, auditable via the locks() polymorphic relation (good where "who held this and when" matters for support or compliance). That's a genuine product knob: do we need lock records to survive a cache flush?
  • Scoping/ownership semantics: the automatic owner detection (user_id, job ID, request hash) means "a worker only releases what it owns." That's a correctness decision that most hand-rolled implementations get wrong, and it's worth standardizing centrally rather than re-deriving per team.

Use cases that map cleanly: duplicate payment/refund processing, inventory decrement at checkout, webhook processing idempotency guards, financial transfer coordination, single-flight cron, admin "don't let two support agents act on the same ticket" guards.

When to Consider This Package

Adopt when most of these are true:

  • You have more than a handful of concurrency-sensitive endpoints/jobs, so a shared abstraction pays for itself versus scattered Cache::lock() calls with ad-hoc key naming.
  • Locks are naturally entity-scoped (per user, per order, per account) — that's the package's core assumption and where it reads best.
  • Your stack is Laravel 11–13, PHP 8.2+, with Redis/Memcached already present, or you're willing to add a locks table.
  • You want declarative route protection and consistent 429 behavior across services rather than per-team implementations.
  • You need lock history/persistence (database driver + Prunable + polymorphic locks() relation) for support debugging or audit.
  • The team values Laravel-native ergonomics (HasLocks, facade, events) over a bespoke internal utility.

Look elsewhere / do additional diligence when:

  • Correctness is non-negotiable for external side effects. TTL-based locks can be held past expiry by a stalled process, producing two "owners." No lock library fixes this alone — you need fencing tokens or idempotency keys at the boundary (e.g., at the payment provider). Treat this package as reducing duplicate work, not as a proof of mutual exclusion.
  • You only have one or two lock sites. Cache::lock() is free, battle-tested, and already in the framework. A dependency isn't justified for two call sites.
  • Vendor/maturity risk matters. 43 stars, 0 public dependents, a single-maintainer ecosystem package, and an early release line. For a payments path, that's a real consideration — mitigate by wrapping it behind an internal interface, or prefer the framework primitive.
  • Throughput is high. The database driver costs writes and rows per request; measure before putting it in front of a hot endpoint. Cache driver + Redis is the right shape there.
  • You need multi-region/strong consistency guarantees, lock reentrancy, fair queuing, or sub-millisecond contention at scale — go to a dedicated coordination system.
  • Your contention is cross-language/cross-service. A PHP-only lock can't coordinate with a Go service without sharing the same Redis key convention; at that point define the contract explicitly.
  • Nobody will own the operational pieces: model:prune scheduling, cache-store durability settings, alerting on LockFailed.

Recommended diligence gates before adoption: a staging load test on the hottest endpoint, a documented decision on driver-per-use-case, a written statement of what fencing you rely on for money movement, and a review of what happens on cache flush/deploy.

How to Pitch It (Stakeholders)

To executives (1–2 minutes): "We lose money and trust when two copies of the same operation run at once — double charges, oversold inventory, duplicate webhooks. Today each team solves that differently, or doesn't. This is a small, MIT-licensed Laravel library that standardizes it in a few lines: 'only one of these may run at a time for this user/order,' with automatic cleanup and audit events. Integration is roughly a day of work, no new infrastructure if we already run Redis, and it removes an entire class of incident rather than one bug. It's a small open-source dependency from a single maintainer, so we'll isolate it behind our own thin interface — that keeps the ergonomics while making it a two-hour swap if we ever need to. Ask: approve a one-sprint pilot on the billing endpoint, success measured by duplicate-charge incidents and lock-contention alerts."

To engineering leadership: "It's the missing middle layer between Cache::lock() and a bespoke locking service. Same primitive underneath; the value is owner detection (only the holder releases), Eloquent scoping, middleware with correct finally semantics, swappable cache/database stores, and typed lifecycle events for monitoring. Realistic cost: half a day to integrate and configure, plus decisions on driver-per-use-case and prune scheduling. Main risk isn't the code — it's treating any TTL lock as a correctness guarantee. We should pair it with idempotency keys on anything touching money, and keep an internal LockManager-shaped interface so the vendor dependency stays shallow. If we only ever need one lock site, use the framework primitive instead; the case for this package is standardization across several."

To the team (practical framing): "Use Lock::for(...)->block(...) for burst-prone work, the middleware for endpoint-level single-flight, and the database driver only where we need to answer 'who held this and when.' Watch the LockFailed event volume — rising contention means a lock is too broad, not that we need more servers."

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel