Laravel Queue

Handle Skipped Unique Jobs with UniqueJobSkipped

Punyapal Shah
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.

Tags: #Laravel #Queue #Events
Share on X

// Found an issue or want to contribute a tip? github.com/MrPunyapal/tips