From 6c46fa03c27aa1c25c6f584fd5c54b1d15d0a2ce Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 29 Sep 2016 15:38:54 -0500 Subject: [PATCH] Granular notification queue jobs This tweaks notification queued job to queue a job for each notifiable / channel combination. The reason for this is with the prior setup of using a single job, if one channel fails to send and the job retries all channels you could deliver duplicate/N number of notifications on a given channel, possibly costing you money if the channel charges money per notification. --- .../Notifications/ChannelManager.php | 26 +++++++++++++------ .../Notifications/SendQueuedNotifications.php | 13 ++++++++-- ...NotificationSendQueuedNotificationTest.php | 2 +- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Notifications/ChannelManager.php b/src/Illuminate/Notifications/ChannelManager.php index 5f89e829b895..d89b16ad6194 100644 --- a/src/Illuminate/Notifications/ChannelManager.php +++ b/src/Illuminate/Notifications/ChannelManager.php @@ -50,7 +50,7 @@ public function send($notifiables, $notification) * @param mixed $notification * @return void */ - public function sendNow($notifiables, $notification) + public function sendNow($notifiables, $notification, array $channels = null) { if (! $notifiables instanceof Collection && ! is_array($notifiables)) { $notifiables = [$notifiables]; @@ -61,7 +61,7 @@ public function sendNow($notifiables, $notification) foreach ($notifiables as $notifiable) { $notificationId = (string) Uuid::uuid4(); - $channels = $notification->via($notifiable); + $channels = $channels ?: $notification->via($notifiable); if (empty($channels)) { continue; @@ -109,12 +109,22 @@ protected function shouldSendNotification($notifiable, $notification, $channel) */ protected function queueNotification($notifiables, $notification) { - $this->app->make(Bus::class)->dispatch( - (new SendQueuedNotifications($notifiables, $notification)) - ->onConnection($notification->connection) - ->onQueue($notification->queue) - ->delay($notification->delay) - ); + if (! $notifiables instanceof Collection && ! is_array($notifiables)) { + $notifiables = [$notifiables]; + } + + $bus = $this->app->make(Bus::class); + + foreach ($notifiables as $notifiable) { + foreach ($notification->via($notifiable) as $channel) { + $bus->dispatch( + (new SendQueuedNotifications($notifiables, $notification, [$channel])) + ->onConnection($notification->connection) + ->onQueue($notification->queue) + ->delay($notification->delay) + ); + } + } } /** diff --git a/src/Illuminate/Notifications/SendQueuedNotifications.php b/src/Illuminate/Notifications/SendQueuedNotifications.php index c829bec7f487..6a816c5c22b8 100644 --- a/src/Illuminate/Notifications/SendQueuedNotifications.php +++ b/src/Illuminate/Notifications/SendQueuedNotifications.php @@ -24,15 +24,24 @@ class SendQueuedNotifications implements ShouldQueue */ protected $notification; + /** + * All of the channels to send the notification too. + * + * @var array + */ + protected $channels = null; + /** * Create a new job instance. * * @param \Illuminate\Support\Collection $notifiables * @param \Illuminate\Notifications\Notification $notification + * @param array $channels * @return void */ - public function __construct($notifiables, $notification) + public function __construct($notifiables, $notification, array $channels = null) { + $this->channels = $channels; $this->notifiables = $notifiables; $this->notification = $notification; } @@ -45,6 +54,6 @@ public function __construct($notifiables, $notification) */ public function handle(ChannelManager $manager) { - $manager->sendNow($this->notifiables, $this->notification); + $manager->sendNow($this->notifiables, $this->notification, $this->channels); } } diff --git a/tests/Notifications/NotificationSendQueuedNotificationTest.php b/tests/Notifications/NotificationSendQueuedNotificationTest.php index 9991cdc04d6d..e9bebbc62ac8 100644 --- a/tests/Notifications/NotificationSendQueuedNotificationTest.php +++ b/tests/Notifications/NotificationSendQueuedNotificationTest.php @@ -13,7 +13,7 @@ public function testNotificationsCanBeSent() { $job = new SendQueuedNotifications('notifiables', 'notification'); $manager = Mockery::mock('Illuminate\Notifications\ChannelManager'); - $manager->shouldReceive('sendNow')->once()->with('notifiables', 'notification'); + $manager->shouldReceive('sendNow')->once()->with('notifiables', 'notification', null); $job->handle($manager); } }