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 Unique Job Locks Laravel Package

mohannadelemary/laravel-unique-job-locks

Prevent duplicate Laravel queue jobs from running at the same time. This package adds unique locks to dispatched jobs so identical tasks are skipped or deduplicated until the first one finishes. Simple setup, configurable lock keys and TTLs, and support for Redis and other cache stores.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Build vs. buy for queue observability. The failure mode this addresses — a ShouldBeUnique job that silently refuses to dispatch because a stale lock is held — normally gets diagnosed by an engineer SSH-ing into Redis and hand-decoding cache/connection prefixes. That's an afternoon of senior time per incident. Two read-only Artisan commands are a very cheap "buy," and evaluating them forces the useful question of whether you should instead build lock introspection into your own internal ops tooling.
  • Roadmap and platform investments. If your product surface depends on background work (billing runs, exports, webhooks, scheduled reports), "job didn't dispatch" incidents look like product bugs to customers and support. This package is a concrete, low-cost lever on queue reliability MTTR, which is often an unowned line item on the roadmap.
  • Standardizing on ShouldBeUnique conventions. The why command surfaces the resolved uniqueVia() store, lock connection, and exact Redis key including cache and connection prefixes. That is decision-support for whether your teams should standardize uniqueVia(), how you name unique IDs (tenant-scoped vs. global), and whether you should be setting uniqueFor TTLs deliberately rather than by default.
  • Incident triage runbooks. The command's diagnostic taxonomy — still queued, worker running, worker probably crashed, orphaned (e.g., after queue:clear) — maps directly onto support escalation scripts. It converts an ambiguous "the job isn't running" ticket into a classified cause, which affects staffing and on-call expectations.
  • Operational safety posture. Read-only by default, an interactive confirmation before --release, and a check that the lock owner hasn't changed since inspection are exactly the guardrails you'd want before letting a broader set of engineers touch production locks. That shapes whether you permit self-serve remediation by support engineers or restrict it to on-call.
  • Tooling adoption decisions. Whether to add this to your incident-response toolkit, bake it into a container image / ops bastion, or cite it in an internal runbook — all cheap, reversible calls. --job= filtering and --limit= on the queue search matter for whether it's usable against large production queues.

When to Consider This Package

Consider it when most of these are true:

  • You use ShouldBeUnique or ShouldBeUniqueUntilProcessing in production, and "the job didn't dispatch" is a recurring or feared incident class.
  • Your unique-job locks live in a Redis cache store (phpredis or predis) — this is a hard requirement today.
  • You're on Laravel 12/13 and PHP 8.3+. Older versions are not supported.
  • You want read-only diagnostics first: the default mode inspects without mutating, which is appropriate for a first production deployment.
  • You have a plausible owner for the tool — an on-call rotation, platform team, or support escalation path that will actually use the commands.
  • You need to explain why a lock is held, not just that it exists; the four-way classification and the --release owner-change check are the differentiating features versus a generic Redis key dump.

Look elsewhere, or wait, when:

  • Your locks are in a database cache store. Support is explicitly "planned," not shipped. Do not adopt on the promise of a future release.
  • You're on older Laravel or PHP. No stated backport path; this is a greenfield package targeting current versions.
  • You need automated monitoring, alerting, or metrics. This is a CLI for humans. There are no exports, no Prometheus metrics, no scheduled checks, and no programmatic exit-code contract described. If you want "page me when N locks are older than X," this isn't that.
  • You need scripted or CI-driven lock release. --release asks before acting, which is the right safety default but is a poor fit for automation. Treat it as an interactive operator tool.
  • You require vendor guarantees. This is a v0.1.0 first release from a single maintainer with no track record, no stated deprecation policy, no security disclosure process, and no evidence of a support commitment. For a tool that touches production caches, weigh that against the fact that it is read-only by default and small enough to vendor or fork.
  • You need multi-tenant or role-based access control around who can inspect or release locks. Access is whoever can run Artisan against the environment — no authorization model beyond that.
  • You want a full queue-observability platform (Horizon-style dashboards, historical data, throughput/latency trends). This is a narrow point tool for one specific lock-semantics problem.

Adoption guidance: treat v0.1.0 as a trial. Pin the version, install it in staging first, and validate the why output against a lock you create intentionally. The --release path in particular deserves a staging rehearsal — it's the only mutating behavior and the owner-change guard is worth confirming empirically before anyone runs it against a shared production queue.

How to Pitch It (Stakeholders)

For executives: This is a small, free, open-source command-line tool that shortens the time to fix a specific class of production incident — background jobs that quietly fail to run because a stale lock is stuck in Redis. Those incidents are invisible in logs, look like product bugs to customers, and typically burn senior engineering hours in manual Redis archaeology. The cost is one Composer dependency and two Artisan commands; there is no application code change, no new service, no schema change, and no data migration. It is read-only by default, and the one destructive capability is gated behind an interactive confirmation and an ownership check. It is early-stage software (v0.1.0, one maintainer, Redis-only, Laravel 12/13 and PHP 8.3+), so the recommendation is a bounded trial in staging and a single production pilot — not a broad rollout. Framed on the roadmap, it belongs under operational tooling and reliability, not product features; the honest justification is MTTR reduction on queue incidents and a cleaner support escalation path, and the honest risk is maintainer and maturity risk for a tool we could replace with our own script if it stalls.

For engineering: Two commands, queue:unique-locks and queue:unique-lock:why {job} --id=. The first lists held locks with job, unique ID, TTL remaining, and owner, with --job= to filter by class. The second explains a single lock: the resolved store (uniqueVia() is respected — so this works with your existing per-job configuration), the lock connection, and the exact underlying Redis key including cache and connection prefixes, which is precisely the part that makes manual debugging tedious. It classifies the cause as still queued, worker running, worker probably crashed, or orphaned (including after queue:clear) — note "probably crashed" is an inference from lock state, not a heartbeat, so treat it as a hypothesis to confirm. --limit= bounds how many jobs the queue search reads, which is what makes it safe against a large production queue. Both commands are read-only by default. --release prompts before doing anything and refuses if the lock owner has changed since inspection, which handles the race where a job picks the lock up between your inspection and your cleanup. Requirements are Redis cache store with phpredis or predis, PHP 8.3+, Laravel 12/13; database-store support is planned but not available. Plan: pin the version, exercise it in staging against a deliberately orphaned lock, confirm the why output matches what you injected, rehearse --release, then pilot on one production environment with the team that owns the on-call rotation. Expect to revisit if the database store lands or if the package goes unmaintained.

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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib