Laravel 13.26 New Published on

Handling only the last event of a burst with #[DebounceFor]

A queued listener with #[DebounceFor] waits for the burst to end and handles only the last event, where ShouldBeUnique kept the first one.

Topics covered: QueuesEvents

New in Laravel 13.26. When a product is changed several times in a row, reindexing on every change is expensive. The usual workaround, ShouldBeUnique, discards the duplicates… but keeps the first event: the index receives a version that is already stale. The #[DebounceFor] attribute waits for the burst to end and handles only the last event.

Before

class MettreAJourLIndex implements ShouldQueue, ShouldBeUnique
{
    public int $uniqueFor = 30;

    public function uniqueId(ProduitModifie $event): string
    {
        return (string) $event->productId;
    }
}

Since Laravel 13.26

#[DebounceFor(30)]
class MettreAJourLIndex implements ShouldQueue
{
    public function debounceId(ProduitModifie $event): string
    {
        return (string) $event->productId;
    }
}

Each event is queued with a 30-second delay. When it is about to be handled, Laravel discards the ones that a more recent event with the same debounceId has replaced. The maxWait option (#[DebounceFor(30, maxWait: 120)]) keeps a continuous stream from pushing the handling back indefinitely.

Your task

Rewrite MettreAJourLIndex (the listener that updates the search index) with #[DebounceFor]. The tests send bursts of changes into a real queue, then start a worker: each product must be indexed once, with its latest name.

Where the feature comes from: the original pull request.