Skip to content

[13.x] Add PreparesForDispatch interface for Jobs#59879

Merged
taylorotwell merged 3 commits into
laravel:13.xfrom
jackbayliss:13.x-before-dispatch
May 6, 2026
Merged

[13.x] Add PreparesForDispatch interface for Jobs#59879
taylorotwell merged 3 commits into
laravel:13.xfrom
jackbayliss:13.x-before-dispatch

Conversation

@jackbayliss
Copy link
Copy Markdown
Contributor

@jackbayliss jackbayliss commented Apr 27, 2026

TLDR- this adds adds a pre-dispatch hook cause, right now everyone just dumps everything in the handle, but makes the queues busy.

Currently, ShouldBeUnique is great if you're sending one job per item, but this also means your queues can easily get overwhelmed when you run a heavy system, meaning you have to constantly scale infra, as "mo jobs, mo problems" 😎

Naturally, you then start batching multiple items in the same job, but you lose the ShouldBeUnique per item uniqueness.

So to control this, you end up using locks within the job handle, or running your own logic. But this means you could have a queue of 89k jobs where most of them in reality are doing nothing.

We can use dispatchIf, but then I'd have to duplicate the logic if there's multiple dispatch sites or write your own wrapper which feels odd.

We can override the dispatch method on the Job, which is what I did, but it feels hacky IMO so this PR is born.

This PR adds a PreparesForDispatch interface, which is used for the prepareForDispatch method which basically does preparation logic for the job before it's dispatched, it also lets you return false, if for any reason the job shouldn't continue to the queue.

This is ideal when you have certain logic you need to run per job before its physically dispatched, ie if you're dispatching the job from multiple places with arrays of data, and need the same logic. This is all about saving queue capacity.

Video explanation (boring, audio on):

Details
Screen.Recording.2026-04-27.at.18.20.00.mov

Here's a code example:

Details
use Illuminate\Support\Facades\Cache;

class SyncPodcastsJob implements ShouldQueue, PreparesForDispatch // implement PreparesForDispatch ...
{
    use Queueable;

    public function __construct(public array $podcastIds) {} // different users may have requested the same id in their selections..

    public function prepareForDispatch()
    {
        $this->podcastIds = collect($this->podcastIds)
            ->reject(fn ($id) => Cache::has("syncing:{$id}"))
            ->values()
            ->all();

        if (empty($this->podcastIds)) {
            return false; // We skip dispatching it completely, so the queue doesnt have to work the job to discard it anyway..
        }
        
        // We may want to use this to display the to user that its queued...
        Cache::putMany(
            array_fill_keys(
                array_map(fn ($id) => "syncing:{$id}", $this->podcastIds),
                true
            )
        );
    }

    public function handle(): void
    { 
    // We can clear the cache in the handle, if we want..
    }
}

Open to changing the name, I had a bit of back and forth trying to find a fitting name 🤣 it could be ShouldDispatch, but it can edit state, so I went with Preparable

Any questions etc, lmk!

@github-actions
Copy link
Copy Markdown

Thanks for submitting a PR!

Note that draft PRs are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface.

Pull requests that are abandoned in draft may be closed due to inactivity.

@jackbayliss jackbayliss force-pushed the 13.x-before-dispatch branch 2 times, most recently from 40ea3b9 to 1898cef Compare April 27, 2026 15:44
@jackbayliss jackbayliss changed the title [13.x] Add BeforeDispatch interface for Jobs [13.x] Add InteractsWithDispatch interface for Jobs Apr 27, 2026
@jackbayliss jackbayliss changed the title [13.x] Add InteractsWithDispatch interface for Jobs [13.x] Add Preparable interface for Jobs Apr 27, 2026
use snake, I suppose and implements order

mixed up in this

clean up a bit

think harder

wording

Revert "tests"

This reverts commit 360d801.

tests

Update PendingDispatch.php

rename methods

rename

adjust type

Update BeforeDispatch.php

damn you mr cs

doc block

rename.. again
@jackbayliss jackbayliss force-pushed the 13.x-before-dispatch branch from bbb0767 to ef16a2d Compare April 27, 2026 16:39
@timacdonald
Copy link
Copy Markdown
Member

Love this

@jackbayliss
Copy link
Copy Markdown
Contributor Author

jackbayliss commented Apr 27, 2026

@timacdonald Thanks man, I kinda doubted the name so I let it sit in draft for a bit 😄 - I'll send it out tomorrow with new found belief!

@jackbayliss jackbayliss marked this pull request as ready for review April 28, 2026 18:20
@abellion
Copy link
Copy Markdown
Contributor

abellion commented May 6, 2026

Doesn't this feel a bit redundant with job middleware ? The only real difference is where the logic is executed (in the queue worker vs in the current thread), but is that distinction enough to justify a new abstraction ?

If there’s truly a need for this, it might make more sense to model it similarly to middleware, i.e. as a chain/pipeline of callbacks rather than a single prepare() method.

@jackbayliss
Copy link
Copy Markdown
Contributor Author

jackbayliss commented May 6, 2026

@abellion Thanks for the feedback,

Job middleware means the job needs to be queued, so imo yes it's worth the abstraction.
A chain could be nice here, but also didn't wanna overengineer it.

I will leave it to Otwell 🫡

@taylorotwell taylorotwell merged commit 2f99185 into laravel:13.x May 6, 2026
52 checks passed
@taylorotwell
Copy link
Copy Markdown
Member

Slightly tweaked naming.

@taylorotwell
Copy link
Copy Markdown
Member

Thanks!

@jackbayliss jackbayliss changed the title [13.x] Add Preparable interface for Jobs [13.x] Add PreparesForDispatch interface for Jobs May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants