From 28d09dedabe45f8f6e005179f9d21c133e396ab9 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Wed, 26 Aug 2026 09:15:11 -0300 Subject: [PATCH] fix(queue): discard email jobs for deleted purchases --- .../Listeners/SendPurchasePaidEmail.php | 2 + .../Listeners/SendTicketsAvailableEmail.php | 2 + .../QueuedNotificationListenerTest.php | 64 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 tests/Feature/Notification/QueuedNotificationListenerTest.php diff --git a/app/Domains/Notification/Listeners/SendPurchasePaidEmail.php b/app/Domains/Notification/Listeners/SendPurchasePaidEmail.php index da51393..d7304fb 100644 --- a/app/Domains/Notification/Listeners/SendPurchasePaidEmail.php +++ b/app/Domains/Notification/Listeners/SendPurchasePaidEmail.php @@ -5,8 +5,10 @@ namespace App\Domains\Notification\Listeners; use App\Domains\Notification\Services\NotificationMailService; use App\Domains\Purchase\Events\PurchasePaid; use Illuminate\Contracts\Queue\ShouldQueueAfterCommit; +use Illuminate\Queue\Attributes\DeleteWhenMissingModels; use Illuminate\Queue\InteractsWithQueue; +#[DeleteWhenMissingModels] class SendPurchasePaidEmail implements ShouldQueueAfterCommit { use InteractsWithQueue; diff --git a/app/Domains/Notification/Listeners/SendTicketsAvailableEmail.php b/app/Domains/Notification/Listeners/SendTicketsAvailableEmail.php index 53a32a9..649ae97 100644 --- a/app/Domains/Notification/Listeners/SendTicketsAvailableEmail.php +++ b/app/Domains/Notification/Listeners/SendTicketsAvailableEmail.php @@ -5,8 +5,10 @@ namespace App\Domains\Notification\Listeners; use App\Domains\Notification\Events\TicketsAvailable; use App\Domains\Notification\Services\NotificationMailService; use Illuminate\Contracts\Queue\ShouldQueueAfterCommit; +use Illuminate\Queue\Attributes\DeleteWhenMissingModels; use Illuminate\Queue\InteractsWithQueue; +#[DeleteWhenMissingModels] class SendTicketsAvailableEmail implements ShouldQueueAfterCommit { use InteractsWithQueue; diff --git a/tests/Feature/Notification/QueuedNotificationListenerTest.php b/tests/Feature/Notification/QueuedNotificationListenerTest.php new file mode 100644 index 0000000..dc04d47 --- /dev/null +++ b/tests/Feature/Notification/QueuedNotificationListenerTest.php @@ -0,0 +1,64 @@ +dispatchQueuedListener( + PurchasePaid::class, + SendPurchasePaidEmail::class, + new PurchasePaid($this->purchase()), + ); + + $this->assertTrue($job->deleteWhenMissingModels); + } + + public function test_tickets_available_email_is_discarded_when_the_purchase_no_longer_exists(): void + { + $job = $this->dispatchQueuedListener( + TicketsAvailable::class, + SendTicketsAvailableEmail::class, + new TicketsAvailable($this->purchase(), [10, 11]), + ); + + $this->assertTrue($job->deleteWhenMissingModels); + } + + private function dispatchQueuedListener(string $event, string $listener, object $payload): CallQueuedListener + { + Queue::fake(); + Event::forget($event); + Event::listen($event, $listener); + + event($payload); + + $queuedListener = null; + + Queue::assertPushed(CallQueuedListener::class, function (CallQueuedListener $job) use (&$queuedListener): bool { + $queuedListener = $job; + + return true; + }); + + $this->assertInstanceOf(CallQueuedListener::class, $queuedListener); + + return $queuedListener; + } + + private function purchase(): Purchase + { + return (new Purchase)->forceFill(['id' => 123]); + } +}