laravellaravel-queuelaravel-notification

How can I make the laravel queue retry only failed notification channels instead of retrying the whole notification?


My laravel notification has to send messages to 2 channels. But when one channel failed, both channel was been resending message by queue. Is there anyway to solve this without creating a deferent notification?

I try to read from docs but I didn't find any answer. The expected result is to only retry failed channel messages when notification being resent by queue.

As Asked by @matiaslauriti the code in notification are the followings: (Laravel 9, php8.1)

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use App\Mail\MyMail;

class LineLoginNotification extends Notification implements 
ShouldQueue
{
    use Queueable;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
          // Attempt to send the notification via email and MyChannel
        return ['mail'  , MyChannel::class ];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return Mailable
     */
    public function toMail($notifiable)
    {
        return (new MyMail($notifiable))->to($notifiable->email);
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }

    /**
     *
     */
    public function toMyChannelMethod($notifiable){
        $msg = "myMsg";
        return $msg;
    }
}

The code of the channel is

<?php

namespace App\Notifications;

use App\Services\MyMessageService;

class MyChannel
{
    /**
     * Send line notification
     * @param $notifiable
     * @param $notification that implements toMyChannelMethod() method
     * @return void
     */
    public function send($notifiable, $notification)
    {
        $line_id = $notifiable->line_id;
        $msg = $notification->toMyChannelMethod($notifiable);
        $messageService = new MyMessageService();

        $messageService->sendSimpleMsg($msg, $line_id);
    }
}

Solution

  • As far as I know Laravel creates separate queued jobs for each channel implemented in queued notifications. When executed by horizon or the default laravel worker each of these jobs instantiates \App\Notifications\LineLoginNotification separately for each channel, 'mail' and MyChannel in your case. So, you should not bother that failing in sending by one notification channel might cause fail in other channels. They don't interfere as long as your notification implements ShouldQueue interface.

    Update: by the way, maybe you are already aware of but just FYI, you should add an attribute

    public $tries = 3; // number of retries
    

    to your notification class \App\Notifications\LineLoginNotification or indicate 'tries' attribute in your horizon configuration (config/horizon.php) in order a failed notification to be retried by queue worker.