From the Laravel manual, I understand that I can limit the number of times a queued job is retried using either the command line (when starting the queue), or by setting the $tries property on the job class itself. https://laravel.com/docs/5.6/queues#max-job-attempts-and-timeout
I want to set the maximum number of retries within the job itself, not using the command line, however the job is actually a custom class that inherits from Illuminate\Notifications\Notification, not an App\Job. In this case, is it possible to limit the number of tries?
I tried setting the $tries property in my customer notification, but it had no effect. I am using a custom channel as well, but setting the $tries there had no effect either.
In your notification file add the Queueable trait. It's this trait that gives you the possibility to alter the number of tries.
use Illuminate\Bus\Queueable;
class MyNotification extends Notification implements ShouldQueue
{
use Queueable;
public $tries = 3;
As of Laravel 5.7+, you can easily limit maximum tries by adding $tries property to the Queueable Notification.
Usage example from the PR author (laravel/framework GitHub PR 26493#):
<?php
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class TestNotification extends Notification implements ShouldQueue
{
use Queueable;
public $tries = 3; // Max tries
public $timeout = 15; // Timeout seconds
/**
* 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)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
}
Related
I want to implement email notifications for some events. Also I was this events to be processed asynchronosly using Laravel database queue.
Here is what I have:
Event class:
<?php
namespace App\Events;
use App\Models\ServerReviewVote;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class NewServerReviewVote
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(public ServerReviewVote $serverReviewVote)
{
}
}
Listener class:
<?php
namespace App\Listeners;
use App\Events\NewServerReviewVote;
use App\Notifications\NewServerReviewVote as NewServerReviewVoteNotification;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendNewServerReviewVoteNotification implements ShouldQueue
{
/**
* Handle the event.
*
* #param NewServerReviewVote $event
* #return void
*/
public function handle(NewServerReviewVote $event)
{
$event->serverReviewVote->serverReview->author
->notify(new NewServerReviewVoteNotification($event->serverReviewVote->serverReview));
}
}
Notification class:
<?php
namespace App\Notifications;
use App\Models\ServerReview;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class NewServerReviewVote extends Notification implements ShouldQueue
{
use Queueable;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(private ServerReview $serverReview)
{
}
/**
* Get the notification's delivery channels.
*
* #param User $notifiable
* #return array
*/
public function via(User $notifiable): array
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param User $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail(User $notifiable): MailMessage
{
return (new MailMessage)
->subject('New vote for your review!')
->greeting("Hello, {$notifiable->name}!")
->line("We got a new vote for your review for {$this->serverReview->server->name} server!")
->line("Your review currently have {$this->serverReview->votesUpCount()} upvotes and {$this->serverReview->votesDownCount()} downvotes.")
->line("Click the button below to navigate to the server page:")
->action($this->serverReview->server->name, route('servers.show', ['server' => $this->serverReview->server->slug]));
}
}
I'm firing event from this observer:
<?php
namespace App\Observers;
use App\Events\NewServerReviewVote;
use App\Models\ServerReviewVote;
class ServerReviewVoteObserver
{
/**
* #param ServerReviewVote $serverReviewVote
*/
public static function created(ServerReviewVote $serverReviewVote)
{
event(new NewServerReviewVote($serverReviewVote));
}
}
I configured queue database driver and my database has jobs table.
My expectations is that this event will be added to this table and than I can process it by using php artisan queue:work. But for some reason email sends synchronously instead of adding to queue. What have I missed?
Ok, I've been trying different ways and found how to make listeners to be added to queue.
I added public $connection = 'database' property to listener class.
Here is how it looks now:
<?php
namespace App\Listeners;
use App\Events\NewServerReviewVote;
use App\Notifications\NewServerReviewVote as NewServerReviewVoteNotification;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendNewServerReviewVoteNotification implements ShouldQueue
{
/**
* Connection for queue
* #var string
*/
public string $connection = 'database';
/**
* Handle the event.
*
* #param NewServerReviewVote $event
* #return void
*/
public function handle(NewServerReviewVote $event)
{
$event->serverReviewVote->serverReview->author
->notify(new NewServerReviewVoteNotification($event->serverReviewVote->serverReview));
}
}
As far as I understood from Laravel docs this property isn't required but for some reason listener didn't dispatch to queue without it. Now it works good!
Also I cleared notification class as it doesn't need to implement ShouldQueue interface and use Queueable trait.
Here is how it looks now:
<?php
namespace App\Notifications;
use App\Models\ServerReview;
use App\Models\User;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class NewServerReviewVote extends Notification
{
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(private ServerReview $serverReview)
{
}
/**
* Get the notification's delivery channels.
*
* #param User $notifiable
* #return array
*/
public function via(User $notifiable): array
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param User $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail(User $notifiable): MailMessage
{
return (new MailMessage)
->subject('New vote for your review!')
->greeting("Hello, {$notifiable->name}!")
->line("We got a new vote for your review for {$this->serverReview->server->name} server!")
->line("Your review currently have {$this->serverReview->votesUpCount()} upvotes and {$this->serverReview->votesDownCount()} downvotes.")
->line("Click the button below to navigate to the server page:")
->action($this->serverReview->server->name, route('servers.show', ['server' => $this->serverReview->server->slug]));
}
}
Now listener successfully dispatching to jobs table and can be processed by running php artisan queue:work database
I am able to fire dummy events from the Pusher debug console and my client side is able to pick them up. But when I try to fire the event from my UserController nothing seems to happen.
Here is my Event class
<?php
namespace App\Events;
use App\Events\Event;
use App\Player;
use App\Product;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class NewPurchase extends Event implements ShouldBroadcast
{
use SerializesModels;
public $product;
/**
* Create a new event instance.
*
* #param Product $product
* #return void
*/
public function __construct(Product $product)
{
$this->product = $product;
}
/**
* Get the channels the event should be broadcast on.
*
* #return array
*/
public function broadcastOn()
{
return [Player::where('user_id', $this->product->seller_id)->first()->group_id];
}
}
Here is my listener, which doesn't have anything because I want everything to be process client side
<?php
namespace App\Listeners;
use App\Events\NewPurchase;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class NewPurchaseListener implements ShouldQueue
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param NewPurchase $event
* #return void
*/
public function handle(NewPurchase $event)
{
//
}
}
Here is my .env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=858577
PUSHER_APP_KEY=ec160cc0a1ca15e463f4
PUSHER_APP_SECRET=
QUEUE_DRIVER=sync
Here is my event service provider
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
'App\Events\NewPurchase' => [
'App\Listeners\NewPurchaseListener',
],
];
And here is where the event is fired
Event::fire(new NewPurchase($product));
My issue was that my version of Laravel hadn't been updated from the previous developers. Therefore the version of Pusher I had wasn't compatible at first with the version of Laravel I was using. I have tweaked this now and it works.
I'm trying to send email to members on my app and I get the following error:
production.ERROR: Call to undefined method
Illuminate\Database\Query\Builder::routeNotificationFor()
{"exception":"[object] (BadMethodCallException(code: 0): Call to
undefined method
Illuminate\Database\Query\Builder::routeNotificationFor() at
/var/www/vhosts/.../laravel/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2483)
I have the members model with the Notifiable trait and the weird issue is that on my local machine the emails are delivered... The problem is on production...
Any ideas?
The notifications are fired with:
Notification::send($members_to_notify, new CommMessage($communication));
And the CommMessageclass is:
CommMessage.php
namespace App\Notifications\Communications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use App\Mail\Communications\Message as Mailable;
class CommMessage extends Notification implements ShouldQueue
{
use Queueable;
private $communication;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($communication)
{
$this->communication = $communication;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return Mailable
*/
public function toMail($notifiable)
{
return (new Mailable($this->communication))->to($notifiable->email);
}
}
The mailable Message class is:
Message.php
namespace App\Mail\Communications;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class Message extends Mailable
{
use Queueable, SerializesModels;
/**
* The appointment instance.
*
* #var Appointment
*/
public $communication;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($communication)
{
$this->communication = $communication;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$this->replyTo($this->communication->school->email)
->markdown('emails.communications.message');
$this->subject($this->communication->title);
$this->withSwiftMessage(function ($message) {
$message->getHeaders()
->addTextHeader('X-Mailgun-Variables', json_encode([
'model_id' => $this->communication->id,
'model' => get_class($this->communication),
'email_type' => 11 //Communication message (EmailLogType)
]));
});
}
}
This issue was solved. Code has no errors, I was using Supervisor to manage queues and I have forgot to restart it on production server.
I Am sending emails in Laravel Queue. While using the send method, as shown here
Mail::to($userSocial->getEmail())->send(new WelcomeEmail('1234567', "haha", "Makamu"));
my email is delivered to my inbox. However when i switch to queue like below
Mail::to($userSocial->getEmail())->queue(new WelcomeEmail('1234567', "haha", "Makamu"));
I also used this method
SendEmailSocialReg::dispatch('12345678', "haha", "Makamu");
and monitor via queue:listen i am get the processing. then processed message. No error however.
What could be wrong?
my WelcomeEmail
<?php
namespace App\Mail;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class WelcomeEmail extends Mailable
{
use Queueable, SerializesModels;
public $password;
public $client_name;
public $client_email;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($password, $email, $name)
{
$this->password = $password;
$this->client_name = $name;
$this->client_email = $email;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('email.auto');
}
}
Your WelcomeEmail class must return markdown() at build() function like this:
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('email.auto');
}
Then the queue worker must be executed with this command:
php artisan queue:work --queue=default
I need to get an original Request (specifically Request::server()) in my listeners for these Laravel internal events:
Illuminate\Auth\Events\Login
Illuminate\Auth\Events\Failed
Understandably, I cannot use values Request returns in my listener, since it's constructed separately server-side on queue.
Any help is highly appreciated!
In the constructor of the listener you can save the request to a member of the class, then you will be able to use it inside the handle function. For example:
class LogSuccessfulLogin implements ShouldQueue
{
protected $request;
/**
* Create the event listener.
*
* #return void
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Handle the event.
*
* #param Login $event
* #return void
*/
public function handle(Login $event)
{
// here you can use $this->request->ip(); for example.
}
}