webonaute/doctrine-datalocking-bundle
A Symfony bundle that brings data locking to Doctrine entities, helping prevent concurrent modification conflicts and keeping persistence safe with minimal configuration.
Architecture fit. webonaute/doctrine-datalocking-bundle is not a Laravel package — it is a Symfony bundle built on Doctrine ORM. Its mechanism is straightforward: register a side table of lock records keyed to entity identifiers, acquire a lock over a homogeneous list of entities, return a generated lock ID, and hand that ID to a single worker/processor that then acts on the list. The capability is real and the concept (batch claim with a fencing handle) is a sound pattern for work-queue-over-relational-data. The packaging, however, assumes Symfony's DI container, DoctrineBundle configuration, and Doctrine's UnitOfWork/event-listener lifecycle. A Laravel/Eloquent application would be adopting the bundle's runtime dependencies more than its value.
Integration feasibility. Low as-is. Three paths exist: (1) add Doctrine ORM to Laravel via laravel-doctrine/orm and wire the bundle through a compatibility shim — heavy, and the shim becomes ours to maintain; (2) vendor the lock algorithm and reimplement it against Eloquent, which is roughly a locks table, an atomic claim query, and a release path; (3) treat the repo as a design reference only. Given the size of the actual algorithm, path (2) is the only defensible option and it is measured in days, not weeks.
Technical risk. High, concentrated in three areas. Correctness: the entire value proposition rests on the acquire step being atomic under concurrent workers. That requires either a unique constraint on the entity-key range plus insert-or-fail, or a row-claiming UPDATE ... RETURNING / SELECT ... FOR UPDATE SKIP LOCKED. The README does not document which guarantee is provided, and there is no evidence of concurrency testing. A race here means double-processing, which is worse than no lock at all. Liveness: there is no documented TTL, lease renewal, or reclaim path for locks held by a crashed worker — a stuck lock silently stalls a shard of the queue. Currency: last release 2022-05-25, 2 stars, 0 dependents, MIT, single-maintainer risk. It almost certainly targets Symfony 5/6 and Doctrine ORM 2.x; modern Symfony 7 / Doctrine ORM 3 and PHP 8.3+ are untested territory. Score 0.01 is consistent with "abandoned, not merely quiet."
Key questions for the maintainer (or for our own spike if we reimplement).
composer.json?Stack fit. Misaligned at the framework layer, aligned at the data layer. Our application is Laravel + Eloquent; the package expects Symfony + Doctrine. The underlying primitive — claim a set of rows, get a token, process, release — is engine-agnostic and maps cleanly onto MySQL/Postgres, which we already run.
Migration path. Recommend a concept port, not a dependency adoption. Extract the acquire/release semantics into an internal BatchLock service: a locks table with lock_id (UUID), entity_type, entity_id, acquired_at, expires_at, owner, and a unique index on (entity_type, entity_id) for held locks. Acquisition becomes a single atomic insert-many or an UPDATE ... WHERE lock_id IS NULL RETURNING depending on engine. Release is a delete or a null-out. This is a two-to-three day build plus tests, and it removes the framework coupling entirely.
Compatibility. If we were to attempt the Symfony bundle route, we would be pinning Doctrine ORM 2.x and an older Symfony range, then maintaining a DI shim with no upstream support. The version-drift cost compounds every time we touch the ORM. Laravel 10/11 has no native support path. Treat the package as greenfield-only and not recommended even there.
Sequencing.
SKIP LOCKED sufficient? Most queue-over-DB workloads need the latter and it is far simpler.app/Support/ with a pinned commit hash and a note that we own it.Maintenance. Effectively zero upstream maintenance since May 2022. Adopting it means owning a fork on day one: security patches, PHP/Symfony/Doctrine upgrades, and database driver changes are all ours. With 2 stars and 0 dependents, there is no user community to surface bugs or share fixes. Budget for a permanent line item, or avoid it.
Support. No vendor, no SLA, no issue triage velocity, no documentation beyond a README. Internal escalation would land on whichever engineer wrote the integration — a single point of failure.
Scaling. The lock table becomes a write hotspot. Behavior degrades with contention as worker count grows: every claim is a write plus index maintenance. Batch size is the primary tuning knob (larger batches amortize lock overhead but increase the blast radius of a stale lock and lengthen hold times). Horizontal worker scaling is bounded by database write throughput, not by application CPU — worth stating explicitly to whoever owns capacity planning.
Failure modes to instrument for.
finally semantics.Ramp-up. The concept is small enough that a mid-level engineer can read the README in ten minutes. The risk is not comprehension, it is debugging: concurrency defects here are intermittent and require someone fluent in transaction isolation levels and engine-specific locking behavior. Staff the build with a senior backend engineer and require a concurrent-worker test harness as an acceptance criterion, not an afterthought.
Recommendation. Do not adopt. The capability is worth roughly 150 lines and two days of engineering; the dependency costs a permanent maintenance obligation and an untested concurrency contract. Close the evaluation with a written "build in-house" decision and a link to this assessment.
How can I help you explore Laravel packages today?