Laravel provides a queue interface to help you defer long-running tasks such as sending emails/SMS, file processing, etc. As much as you try to avoid it, your queue will fail sometimes and because these failures are ignored by default, you need a way to be notified. In this article, we will explore how to send a Slack notification each time a queue fails.
Pre-requisites
Before Laravel 5.8.x, the Slack notification channel was pre-packaged into the framework. If your Laravel version is < 5.8.0, feel free to skip the installation (although you should look into upgrading as Laravel is currently on version 6.0). From Laravel 5.8.x and above, the Slack notification channel is packaged separately from the framework so we have to import it via:
$ composer require laravel/slack-notification-channel
Next, update your .env
file to include your Slack webhook URL. This URL will be used by the Laravel notification to send our message to the associated Slack channel.
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Next, generate a new notification with:
$ php artisan make:notification QueueFailed
Open the newly created file located at APP-FOLDER/app/Notifications/QueueFailed.php
and paste in the following:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\SlackAttachment;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\Events\JobFailed;
class QueueFailed extends Notification
{
use Queueable;
/**
* @var JobFailed
*/
public $event;
/**
* Create a new notification instance.
*
* @param JobFailed $event
*/
public function __construct(JobFailed $event)
{
$this->event = $event;
}
public function via($notifiable)
{
return ['slack'];
}
public function toSlack($notifiable)
{
return (new SlackMessage())
->to("#general")
->content("Job failed at ". config('app.name'))
->attachment(function(SlackAttachment $attachment) use ($notifiable) {
$attachment->fields([
'Payload' => $this>event->job->getRawBody(),
'Exception' => $this>event->exception->getTraceAsString(),
'Job' => $this>event->job->resolveName()
]);
});
}
public function toArray($notifiable)
{
return [
//
];
}
}
Now that our notification and queues are set up, update the boot()
method in our app/Providers/AppServiceProvider.php
file to the one below:
public function boot()
{
$slackUrl = env('SLACK_WEBHOOK_URL');
Queue::failing(function (JobFailed $event) use ($slackUrl) {
Notification::route('slack', $slackUrl)->notify(new QueueFailed($event));
});
}
The Queue::failing()
condition is trigged whenever the handle()
method of your Laravel Job fails. Failure could be the result of an exception being thrown, but regardless of the reason, this will be how we test the Slack notification.
That’s it! You should now get a notification in the #general channel of your Slack group each time a queue fails.
Testing
To test the Slack notification, simply run your job with a condition that would cause the job to fail.
If you’ve used the tutorial “Create a Database Queue to Send SMS in PHP with Laravel Queues and Twilio SMS”, setting the To
field in the database to empty will cause the job to fail.
Conclusion
If you're planning to handle your failed queues separately, you might want to start from the official queue documentation.
In any case, feel free to reach out to me on Twitter @firechael if you have questions or suggestions.