Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here

Dispatch Jobs into Background Queue

Premium
4 min read

Imagine a sequence of actions to be performed "in the background", in addition to creating the main logic.

For example, after user registration, you want to prepare demo data for their dashboard. You may want to put it into the background queue so the user won't wait for the operation to finish.

This is where Job classes come to help you.

Jobs are similar to Actions we discussed earlier, but Jobs may be put in a Queue. And they have Artisan command to create them:

php artisan make:job NewUserDataJob

And our job would look like this:

app/Jobs/NewUserDataJob.php:

class NewUserDataJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 
public function __construct(public User $user)
{}
 
public function handle()
{
Project::create([
'user_id' => $this->user->id,
'name' => 'Demo project 1',
]);
 
Category::create([
'user_id' => $this->user->id,
'name' => 'Demo category 1',
]);
 
Category::create([
'user_id' => $this->user->id,
'name' => 'Demo category 2',
]);
}
}

All that's left is to...

The Full Lesson is Only for Premium Members

Want to access all of our courses? (29 h 14 min)

You also get:

54 courses
Premium tutorials
Access to repositories
Private Discord
Get Premium for $129/year or $29/month

Already a member? Login here

Comments & Discussion

A
angel ✓ Link copied!

The question may be out of the scope of this lesson but how to make sure to keep data integrity when the job fails in this code :

class NewUserDataJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 
    public function __construct(public User $user)
    {}
 
    public function handle()
    {
        Project::create([
            'user_id' => $this->user->id,
            'name' => 'Demo project 1',
        ]);
		 // ....
    }
}

let's suppose the user is created but the job fail creating related post. How to handle that ? Should we put the user creation and job dispatching of the project creation in database transaction ?

DB::transaction(function () {
     $user = (new CreateUserAction())->execute($request->validated());
    NewUserDataJob::dispatch($user);
});
M
Modestas ✓ Link copied!

So in this case, I would actually move everything to the inside of a job with a transaction. That way it will be handled mostly automatically, instead of manually reverting :)

Of course, you could use batch jobs and chain them with catch condition, but... that is quite more work to do!

L
LazyDali ✓ Link copied!

This is also outside of this course's scope but the last comment/answer got me wondering : So I guess testing becomes difficult when the DB::transaction() is involved as the transaction will include multiple responsibilities, right? How would you approach such situation? Thanks!

M
Modestas ✓ Link copied!

Hi, I'm not sure why this would make testing hard.

For example, your test assumes that when an action is called - there is N things that happen. Right? Well, it doesn't matter if there was a DB::transaction() or not, as you still check for end result. And if there is no desired end result - your tests will fail.

In other words, you don't care what happens under the hood most of the time. You care about:

  1. Setup of data
  2. Execution was without errors (DB::transaction() fail is not an error!)
  3. Expected outcome was achieved

If anything fails inside of there - you will still fail to see #3 pass. This does include all 500 errors or db failures/malformed data

Q
qais ✓ Link copied!

How should we handle the scenario where a user needs to access information about pending queues in a Laravel application—queues that have not been executed yet? Should this logic be placed directly within the controller, or is there a more appropriate approach to manage this?

M
Modestas ✓ Link copied!

You can request that in the controller - I don't see any issues with that

��
Сергій Каліш ✓ Link copied!

if you need to generate something in the background after creating a user, it is probably more appropriate to put it in the observer

M
Modestas ✓ Link copied!

Not always. Imagine that after creating a user, you need to run a setup script that takes 30 or more seconds to complete. This would mean that the whole setup is sync and the request would hang for that long (even with observers). That's where Jobs come in - they are async meaning that the user loads the page fast, while the Job is processed in the background.

��
Сергій Каліш ✓ Link copied!

I misspoke, I don't mean that you don't need to queue the task, I mean running it not in the controller, but in its own task observer ))