Laravel 13.25 adds the UniqueJobSkipped event, allowing applications to react whenever a unique queue job is skipped because a duplicate instance is already active.
When background tasks prevent duplicate execution using unique locks, skipped dispatches previously occurred without firing a dedicated event. Laravel 13.25 introduces `Illuminate\Queue\Events\UniqueJobSkipped`, which is dispatched whenever a unique job is skipped.
Define a Unique Job
Uniqueness is configured on the job class using the `ShouldBeUnique` interface and the `uniqueId()` method:
namespace App\Jobs;
use App\Models\Product;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
class UpdateProductSearch implements ShouldQueue, ShouldBeUnique
{
public function __construct(
public Product $product,
) {}
// Jobs for the same product share the same unique ID.
public function uniqueId(): string
{
return (string) $this->product->id;
}
public function handle(): void
{
// Update the search index...
}
}
The `ShouldBeUnique` contract instructs Laravel to prevent duplicate instances of the job from queuing concurrently. The `uniqueId()` method defines the unique identifier for lock key resolution. If multiple `UpdateProductSearch` jobs are dispatched for product `1`, they share the same unique ID `"1"`, causing Laravel to skip duplicate dispatches while the original job remains active.
Listen for Skipped Jobs
You can register an event listener for `UniqueJobSkipped` in your `AppServiceProvider` or EventServiceProvider:
use Illuminate\Queue\Events\UniqueJobSkipped;
use Illuminate\Support\Facades\Event;
Event::listen(UniqueJobSkipped::class, function ($event) {
logger()->info(
'Unique job skipped: ' . $event->job->uniqueId(),
[
'job' => $event->job,
]
);
});
The event provides access to the underlying queue job instance via `$event->job`. Accessing `$event->job->uniqueId()` inside your listener includes the specific unique identifier in your logs, making it visible which job instance was skipped.
Why This Is Useful
Listening to `UniqueJobSkipped` helps track queue deduplication across your application:
- Finding Skipped Jobs: Identify the specific unique job instance and ID that was suppressed.
- Logging Duplicate Dispatches: Keep detailed records of when redundant background tasks occur.
- Monitoring Skipped Work: Track metrics and frequency of skipped dispatches in application dashboards.
- Investigating Suppressed Tasks: Confirm whether expected work ran to completion or was suppressed as a duplicate.
Note that `ShouldBeUnique` is what enforces job deduplication, while `uniqueId()` determines the unique identifier. `UniqueJobSkipped` is an event dispatched after a job is skipped; it does not enforce uniqueness by itself or automatically log any data without an explicit event listener.