Reputation: 127
I am learning Laravel, working on a project which runs Horizon to learn about jobs. I am stuck at one place where I need to run the same job a few times one after one.
Here is what I am currently doing
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Subscriptions;
class MailController extends Controller
{
public function sendEmail() {
Subscriptions::all()
->each(function($subscription) {
SendMailJob::dispatch($subscription);
});
}
}
This works fine, except it runs the job's across several workers and not in a guaranteed order. Is there any way to run the jobs one after another?
Upvotes: 3
Views: 24967
Reputation: 4271
To add an extra info on @Josh answer, if one of your jobs implemented Illuminate\Contracts\Queue\ShouldQueue
interface, other jobs in the chain must implement ShouldQueue
interface, otherwise they will not be chained.
For example, here if ProcessPodcast
class implemented ShouldQueue
, OptimizePodcast
also must implement this interface to be included in the chain.
class ProcessPodcast implements ShouldQueue {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
...
}
class OptimizePodcast implements ShouldQueue {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
...
}
Upvotes: 1
Reputation: 199
What you need is Job Chaining.
You can read all about it in the Laravel website : Chain
Good luck
Upvotes: 0
Reputation: 956
What you are looking for, as you mention in your question, is job chaining.
Job chaining allows you to specify a list of queued jobs that should be run in sequence. If one job in the sequence fails, the rest of the jobs will not be run. To execute a queued job chain, you may use the withChain method on any of your dispatchable jobs:
ProcessPodcast::withChain([ new OptimizePodcast, new ReleasePodcast ])->dispatch();
So in your example above
$mailJobs = Subscriptions::all()
->map(function($subscription) {
return new SendMailJob($subscription);
});
Job::withChain($mailJobs)->dispatch()
Should give the expected result!
Update
If you do not want to use an initial job to chain from (like shown in the documentation example above) you should be able to make an empty Job
class that that has use Dispatchable;
. Then you can use my example above
Upvotes: 6
Reputation: 111829
Everything depends on how many queue workers you will run.
If you run single queue worker, those jobs
will be processed in the order they were queued. However, if you run multiple queue workers, obviously they will be run in same time. This is how queues should work. You add some tasks and they might run in same time in different order.
Of course if you want to make sure there is a pause between those jobs
, you could inside each
add some sleep() but assuming you are running this in controller (what might be not a good idea because what in case you have million subscriptions) it might be not the best solution.
Upvotes: 2