New features and improvement in Laravel Jobs and Queues since the original v8.0 release

In this fourth post of the series, I've gathered new features added to Jobs and Queues in Laravel 8. Since the original release of 8.0 back in September 2020, Jobs and Queues got a bunch of significant updates that you don't want to miss. If you want to learn all the ins and outs of this topic, look at Learn Laravel Queues by Mohamed Said. It's one of the best Laravel books out there.

If you're new to this series, make sure also to check out the previous posts:

Collections
Database and Eloquent ORM (1/2)
Database and Eloquent ORM (2/2)

Alright, let's start! I got most code examples and explanations from the PRs and official documentation.

v8.19.0 Introducing Job Encryption (#35527) + v8.25.0 Make Listeners, Mailables, and Notifications accept ShouldBeEncrypted (#36036)

When the ShouldBeEncrypted interface is used, Laravel will encrypt the command inside the payload and decrypt it when it processes. You can apply this to Listeners, Mailables and Notifications as well.

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
 
class UpdateSearchIndex implements ShouldQueue, ShouldBeEncrypted
{
...
}

v8.4.0 Added queue:clear command (#34330)

A convenient Artisan command to clear queues. Works great in development in conjunction with migrate:fresh.

php artisan queue:clear

If you're using Laravel Horizon, you should use the horizon:clear instead:

php artisan horizon:clear

v8.21.0 Added command to clean batches table (#35694)

In addition to clearing the queue, there's also a new command to prune stale entries from the batches database.

php artisan queue:prune-batches

v8.48.0 Added a queue:prune-failed command (#37696)

There's also a new command to prune stale records from the failed_jobs database table.

php artisan queue:prune-failed

v8.10.0 Allow for chains to be added to batches (#34612)

You may define a set of chained jobs within a batch by placing the chained jobs within an array.

Bus::batch([
new Job1(),
[
new Job2(),
new Job3(),
new Job4(),
],
new Job5(),
])->dispatch();

v8.11.0 Added job middleware to prevent overlapping jobs (#34794)

This allows you to prevent job overlaps based on a key. This middleware requires a cache driver that supports locks. In the example below, it prevents job overlaps for the same order ID, so there is only one job at a time for this order.

use Illuminate\Queue\Middleware\WithoutOverlapping;
 
public function middleware()
{
return [new WithoutOverlapping($this->order->id)];
}

v8.11.0 Bring Rate Limiters to Jobs (#34829)

We already had rate-limiting middleware for request throttling. This PR enables the same rate limiter classes and syntax for rate-limiting jobs!

use Illuminate\Queue\Middleware\RateLimited;
 
public function middleware()
{
return [new RateLimited('backups')];
}

v8.45.0 Allow setting middleware on queued Mailables (#37568)

Following the above examples, you can also apply middleware to Mailables.

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Queue\SerializesModels;
 
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
 
public function middleware()
{
return [new RateLimited('limiter')];
}
}

v8.52.0 Support job middleware on queued listeners (#38128)

Following the above examples, you can also apply middleware to Listeners.

use App\Events\PodcastProcessed;
use Illuminate\Queue\Middleware\RateLimited;
 
class SendPodcastNotification
{
public function handle(PodcastProcessed $event)
{
//
}
 
public function middleware()
{
return [new RateLimited('limiter')];
}
}

v8.14.0 Added ability to dispatch unique jobs (#35042)

You may implement the ShouldBeUnique interface on your job class to ensure that only one instance of a specific job is on the queue at any point in time. This one is different from the WithoutOverlapping middleware, as that one only limits the concurrent processing of a job. Unique jobs require a cache driver that supports locks.

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;
 
class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
...
}

v8.19.0 Delay pushing jobs to queue until database transactions are committed (#35422)

You may dispatch jobs within database transactions. When you set the after_commit option to true (in queues.php), Laravel will wait until all open database transactions have been committed before actually dispatching the job.

// Queue connection's configuration array:
 
'redis' => [
'driver' => 'redis',
// ...
'after_commit' => true,
],

You may also chain afterCommit onto your dispatch operation. There's also a beforeCommit method that indicates that a specific job should be dispatched immediately event if the after_commit configuration option is set to true.

DB::transaction(function(){
$user = User::create(...);
 
SendWelcomeEmail::dispatch($user)->afterCommit();
 
// or
 
SendWelcomeEmail::dispatch($user)->beforeCommit();
});

v8.36.0 Added dispatch_sync() helper (#36835) + v8.39.0 Added Illuminate\Foundation\Bus\DispatchesJobs::dispatchSync() (#37063)

As an alternative for dispatch_now, you may use the dispatchSync method to dispatch a job immediately (synchronously). When using this method, the job will not be queued and will be executed immediately within the current process.

$podcast = Podcast::create(...);
 
ProcessPodcast::dispatchSync($podcast);
 
// or
 
dispatch_sync(new ProcessPodcast($podcast));

v8.40.0 Added Illuminate\Bus\PendingBatch::add() (#37151)

Sometimes it may be useful to add additional jobs to a batch from within a batched job. This PR brings an add method on the batch instance that may be accessed via the job's batch method:

use App\Jobs\ImportContacts;
use Illuminate\Support\Collection;
 
public function handle()
{
if ($this->batch()->cancelled()) {
return;
}
 
$this->batch()->add(Collection::times(1000, function () {
return new ImportContacts;
}));
}

v8.43.0 Added Illuminate\Queue\Jobs\Job::shouldFailOnTimeout() (#37450)

This PR adds a $failOnTimeouts job property. When set to true, and the job timeouts, the worker will fail the job immediately despite the $tries or $maxExceptions remaining.

use Illuminate\Contracts\Queue\ShouldQueue;
 
class UpdateSearchIndex implements ShouldQueue
{
/**
* Indicate if the job should be marked as failed on timeout.
*
* @var bool
*/
public $failOnTimeout = true;
}

v8.53.0 Added queue:monitor command (#38168)

This command displays a table of the connections and queues and their sizes.

php artisan queue:monitor

You can use the --max option to specify a desired job count threshold, which defaults to 100. When a queue has a job count that exceeds the threshold, a QueueBusy event will be dispatched. You may listen for this event, for example, to send a notification.

php artisan queue:monitor --max=100