Laravel Notifications Listener Is Useless When Implementing the Queue

落花浮王杯 提交于 2021-02-07 09:35:34

问题


Laravel Version: 5.5.*

PHP Version: 7.1.*

According to the docs https://laravel.com/docs/5.5/notifications it should be super simple to subscribe to Notification events. I've followed the steps in the docs, but my Notifications implement ShouldQueue and they weren't properly populating the event listener. I'm wonder if the issue seems to be in the framework code.

Notice that in the framework github (linked right above), that new Events\NotificationSent($notifiable, $notification, $channel, $response) is only fired from the sendToNotifiable function, which in turn is only fired from the sendNow function. The send function itself, is like this:

public function send($notifiables, $notification)
    {
        $notifiables = $this->formatNotifiables($notifiables);

        if ($notification instanceof ShouldQueue) {
            return $this->queueNotification($notifiables, $notification);
        }

        return $this->sendNow($notifiables, $notification);
    }

That is, as it reads to me, the event will not fire if it is a case of if ($notification instanceof ShouldQueue) { as queueNotification never triggers an event listener. I assume it goes into the queue and then will need to re-trigger the event, but I don't think this is happening, because my NotificationSent listener isn't populated with any data from that class constructor.

EventServiceProvider:

 protected $listen = [
       'Illuminate\Notifications\Events\NotificationSent' => [
        'App\Listeners\NewNotificationListener',
    ],

NewNotificationListener:

<?php

namespace App\Listeners;

use Illuminate\Notifications\Events\NotificationSent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Jobs\SendEmailForNotifications;
use Illuminate\Support\Facades\Log;
class NewNotificationListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
  public function handle(NotificationSent $event)
{
Log:info('Notification Listener:'.' '.var_dump($event));
SendEmailForNotifications::dispatch($event->notification)->delay(now()->addMinutes(10));   
} 
}

var_dump here is empty, I get nothing in my log, just Notification Listener:.

So my question is, why is this and how can I have a Notification event listener while leveraging the Queue as I need to do. Is it something I am doing wrong or is it the framework?


回答1:


Quick answer: Have you restarted your queue worker when you made these modifications?

The NotificationSent on my box is triggered and captured as expected when it's being queued and handled.


When Laravel hit this piece of code in NotificationSender:

if ($notification instanceof ShouldQueue) {
    return $this->queueNotification($notifiables, $notification);
}

It queues the notification using the Queue Dispatcher and store it into your queue. And when your worker pick it up, it unserialise the command, and launches SendQueuedNotifications. This class will then handle the queued notifications, and handle the queue (source):

public function handle(ChannelManager $manager)
{
    $manager->sendNow($this->notifiables, $this->notification, $this->channels);
}

And ChannelManager does this (source):

public function sendNow($notifiables, $notification, array $channels = null)
{
    return (new NotificationSender(
        $this, $this->app->make(Bus::class), $this->app->make(Dispatcher::class))
    )->sendNow($notifiables, $notification, $channels);
}

And there you go. The sendNow in NotificationSender is called. The NotificationSent event should be called in this function.


Edit

This is how I tested it:

  1. Make sure your queue has been set up correctly. I use a database queue, with jobs/failed_jobs table combo.

  2. Create the file app/Listeners/TestListener.php

    <?php
    
    namespace App\Listeners;
    
    use Illuminate\Notifications\Events\NotificationSent;
    
    class TestListener
    {
        public function handle(NotificationSent $event)
        {
            \Log::info(get_class($event));
        }
    }
    
  3. Edit app/Providers/EventServiceProvider.php

    <?php
    
    namespace App\Providers;
    
    use App\Listeners\TestListener;
    use Illuminate\Notifications\Events\NotificationSent;
    use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider;
    
    class EventServiceProvider extends ServiceProvider
    {
        /**
         * The event listener mappings for the application.
         *
         * @var array
         */
        protected $listen = [
            NotificationSent::class => [
                TestListener::class
            ]
        ];
    }
    
  4. Create a dummy notification (send an Hello email):

    <?php
    
    namespace App\Notifications\Users;
    
    use App\Notifications\Notification;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Notifications\Channels\MailChannel;
    use Illuminate\Notifications\Messages\MailMessage;
    
    class WelcomeNotification extends Notification implements ShouldQueue
    {
        use Queueable;
    
        public function via($notifiable)
        {
            return [MailChannel::class];
        }
    
        public function toMail($notifiable)
        {
            return (new MailMessage())
                        ->line('Hello');
        }
    }
    
  5. Restart your queue worker. I simply restart my php artisan queue:work.

  6. Send the notification

    $user->notify(new WelcomeNotification());
    
  7. Check laravel.log, you should have the class name of NotificationSent printed there.

    [2018-03-06 09:51:02] production.INFO: Illuminate\Notifications\Events\NotificationSent  
    


来源:https://stackoverflow.com/questions/49101402/laravel-notifications-listener-is-useless-when-implementing-the-queue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!