sfolador/laravel-locked
sfolador/laravel-locked adds simple record locking to your Laravel Eloquent models, helping prevent conflicting concurrent edits. Lock records before modifying them so simultaneous requests can't overwrite each other's changes.
Architecture fit. sfolador/laravel-locked is a Laravel-native, trait-based extension to Eloquent that lets a model acquire and release locks around critical sections. Architecturally it slots into the places TPMs typically care about — wallet/balance mutations, inventory decrements, state-machine transitions, idempotency guards — without introducing new infrastructure (no Redis cluster to provision, no queue). That is attractive for a monolith or modular monolith already on Eloquent. The trade-off is that locking at the model layer tends to bleed into domain/service logic: the package gives you a mechanism, but the discipline of "where do we actually need a lock" remains an application-design responsibility that no library can enforce.
Integration feasibility. Low friction: a Composer install, optionally a published config/migration, and a trait on the relevant models. A motivated Laravel engineer can wire a proof of concept in an afternoon. The real effort is not installation but the audit — every concurrent write path must be identified and deliberately guarded, and every guard must be reviewed for exception safety. The package cannot tell you which code paths need locking, and over-locking is as damaging (contention, timeouts) as under-locking (data races).
Technical risk. This is the dominant concern. 41 stars, a single maintainer, and a last release of February 2023 mean the package has an immature support footprint and uncertain currency against modern Laravel/PHP versions (Laravel 10/11, PHP 8.2/8.3). Locking correctness is notoriously easy to get subtly wrong: lease/TTL semantics, transaction coupling (a lock released before commit re-opens the race), reentrancy, blocking vs non-blocking acquisition, and behavior across MySQL/Postgres/SQLite. The package's internal mechanism — whether it delegates to database advisory locks, the cache store, or a dedicated table — determines almost everything about whether it is safe in your topology, and that must be verified rather than assumed.
Key questions.
Stack fit. Best suited to a Laravel 9/10 codebase on PHP 8.x with Eloquent as the primary persistence layer and a single primary database. If the application is already using Cache::lock() or database transactions for concurrency control, this package is a candidate to consolidate those ad-hoc patterns — but only after confirming its backend aligns with the existing durability story. It is a poor fit for polyglot or event-sourced architectures where aggregate concurrency is handled at a different boundary.
Migration path. Do not retrofit globally. Select one bounded context with known concurrency pain (payments, inventory, seat reservations) and prove the pattern there. Add the trait to a single model, wrap the critical section in a try/finally-style guard, and codify the behavior with concurrency tests. Only after that context is stable should the pattern be templated for other teams. Treat this as an architectural decision record, not a dependency upgrade.
Compatibility. Verify against the actual production database engine, not SQLite. Test explicitly under queue workers (multiple processes sharing a DB), under read-replica configurations (locks may need the writer connection), and under Octane if used. Confirm the framework version matrix and pin the exact version in composer.json. Where the package delegates to framework primitives, check that those primitives are configured consistently across environments.
Sequencing.
Maintenance. The package is small, MIT-licensed, and stable-looking, but effectively solo-maintained with low community velocity. The realistic posture is to vendor it — fork or pin — and budget for an eventual in-house replacement if upstream activity stalls or a Laravel major version breaks compatibility. The in-house replacement cost is low enough (a cache/DB-advisory lock wrapper) that the strategic dependency risk is manageable, but it must be acknowledged up front.
Support. There is no commercial support and no SLA. Ownership must sit with the adopting team. Escalation is "read the source" — which, given the size, is feasible, but should be planned rather than discovered during an incident.
Scaling. Throughput is bounded by the lock backend. Database advisory locks scale with the database and are safe across horizontally scaled app nodes provided the backend is shared — but they consume database connections under contention. The critical discipline is to keep lock-hold time short: never hold a lock across network I/O, third-party calls, or long-running work. Under high contention, blocking acquisition can produce queueing and timeout cascades that look like an availability incident.
Failure modes. The ones to plan for: leaked locks from crashed or killed processes (mitigated by TTL/lease — but then watch for leases expiring mid-operation); deadlocks from inconsistent lock ordering across models; thundering-herd behavior when a blocking lock releases; silent no-ops if the configured driver is unsupported in an environment; and locks that appear held but aren't transactional, allowing a read-modify-write race to survive. Each of these should have a corresponding test and a dashboard/alert (lock wait time, lock acquisition failures, lock leaks).
Ramp-up. The API surface is small, so a Laravel-fluent engineer reaches productivity in roughly half a day to a day. But correct usage requires concurrency literacy — exception safety, lock ordering, transaction boundaries — that is unevenly distributed on most teams. Plan for a short internal design review and a shared pattern document before broader rollout.
How can I help you explore Laravel packages today?