i have a working project written in laravel, i've integrated Sentry to monitor for errors, i followed instructions on their site, basically just
composer require sentry/sentry-laravel
and in my App/Exceptions/Handler.php
if (app()->bound('sentry') && $this->shouldReport($exception)) {
app('sentry')->captureException($exception);
}
Now this works fine, i see errors in sentry.
But at the other end of the app wherever i use queue, for example i have "forgot password" notification and it implements ShouldQueue class, practically:
<?php
namespace App\Notifications\Auth;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class PasswordResetRequest extends Notification implements ShouldQueue
{
use Queueable;
protected $token;
public function __construct($token)
{
$this->token = $token;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
$url = url('/password/find/'.$this->token);
return (new MailMessage)
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', url($url))
->line('If you did not request a password reset, no further action is required.');
}
}
And when triggered works as expected, i have a new record in jobs table (i have database as queue driver)
now when i start my worker
php artisan queue:work
it stalls it works last job over and over
there is no mail sent or received...
By the way this is only when i have reporting in sentry, if i remove those lines in App/Exceptions/Handler.php in report() method it's all good, also if i remove queue from notification it works, only the combinatio of sentry error reporting and notification queuing is making me a big problem.
Unfortunately, Sentry-laravel doesn't work with queues.
Please, see this issue on their GitHub repo to get more info about it:
https://github.com/getsentry/sentry-laravel/issues/18
There is another issue (open) where they are trying to fix it:
https://github.com/getsentry/sentry-laravel/pull/228
If you really need to put these logs on a queue now you should use https://github.com/twineis/raven-php.
Related
I am using this package to try and send apn notifications in my Laravel app. However, I have followed the documentation on the main page, and when I try to send an apn notification, I can log on the server that the constructor and via methods are called, but I can't figure out why my notification either isn't being sent or isn't being received. My logs have no info from the package either.
How do I troubleshoot this? What am I missing?
MyNotification.php
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use NotificationChannels\Apn\ApnChannel;
use NotificationChannels\Apn\ApnMessage;
class MyNotification extends Notification
{
use Queueable;
public function __construct()
{
Log::debug('MyNotification constructor called');
}
public function via($notifiable)
{
Log::debug('MyNotification via called');
return [ApnChannel::class];
}
public function toApn($notifiable)
{
Log::debug('MyNotification toApn called');
return ApnMessage::create()
->badge(1)
->title('My title')
->body('My body');
}
public function routeNotificationForApn($notifiable)
{
Log::debug('MyNotification routeNotificationForApn called');
return $notifiable->token;
}
}
usage code in MyController.php
public function sendNotification(MyModel $model)
{
// authorization checks here...
$devices = Device::where('user_id', $model->user_id)->get();
Notification::send($devices, new MyNotification());
return response()->json(null, 200);
}
Here is what my broadcasting.php and .env files look like:
Your notification uses Queueable so your notifications are only send if your queue is correctly setup.
You can run your queue locally by running
$ php artisan queue:work
On your console you would also get a feedback if your queued job (your notification) has been submitted successfully (not if it is delivered successfully).
This is also highlighted inside the Laravel docs
Before queueing notifications you should configure your queue and start a worker.
If you need a queue that is probably sth. you need to decide as only you know how much load is the application, how many notifications should be sent.
Taken from the docs:
Sending notifications can take time, especially if the channel needs to make an external API call to deliver the notification. To speed up your application's response time, let your notification be queued by adding the ShouldQueue interface and Queueable trait to your class.
Personal opinion: Make it work without a queue, f. ex. locally, and then add a queue.
If you configured to run your queue with Redis, I would highly recommend to use Laravel Horizon to monitor the jobs in your queue.
Tips for using APN
Configure the APN service correctly in config/broadcasting.php - see Github docs.
The problem was that the function routeNotificationForApn() belongs in the notifiable model (in my instance, Device), not in the MyNotification class.
Removing the use Queueable; is required as well if you don't have a queue set up.
I'm using the Laravel queue through redis to send notifications. But whenever I pass models to the notifications, their properties are outdated when the notification is sent through the queue.
This is basically what I'm doing:
In controller (or somehwere else):
$thing = new Thing(); // Thing is a model in this case.
$thing->name = 'Whatever';
$thing->save();
request()->user()->notify(new SomethingHappened($thing))
SomethingHappened.php:
<?php
namespace App\Notifications;
use App\Thing;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class SomethingHappened extends Notification implements ShouldQueue
{
use Queueable;
public $thing;
public function __construct(Thing $thing)
{
$this->thing = $thing;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
dump($this->thing->name); // null
return (new MailMessage())
// ...
// ...
// ...
;
}
}
Now when I add a delay of a few seconds (i.e. (new SomethingHappened($thing))->delay(now()->addSeconds(5))), the retrieved model is up-to-date. Also, before I deployed enough queue workers (and they were lagging behind on a filling queue), this issue didn't exist. Therefore, it appears now that when queue job gets processed really quickly, it doesn't retrieve the model from the database correctly or the model isn't saved yet. I have no idea why this could be happening, since the save call on the model is clearly executed (synchronously) before dispatching the notification, so there should be no way it isn't saved yet when the job is processed.
I'm running on Kubernetes and using a MySQL database. Everything is on GCP (if this is relevant).
Does anyone have an idea? Adding a delay of a few seconds is not a great solution and shouldn't be necessary.
It appears our database was using too much CPU, causing it to switch to the failover regularly. I think this was the cause of the issue. After implementing tweaks reducing the database load, the problem was resolved. A workaround for this issue would be to add a slight delay (as noted in my question).
I'm not sure why this only seemed to affect notifications, and not other queue jobs or requests. If anyone has a more detailed explanation, feel free to post a new answer.
I would like to send mail to user after creating account on my website and I would like to use queues to send them. I'm using PHP Laravel framework.
My controller handles the request after clicking on "Create account":
class LoginController extends Controller
{
...
public function register(Request $request) {
...
$mail = (new RegisterRequest($user))->onConnection("database")->onQueue("emailsQueue");
Mail::queue($mail);
...
}
}
Then I have this RegisterRequest (mailable) class:
class RegisterRequest extends Mailable
{
use Queueable, SerializesModels;
protected $user;
public function __construct($user)
{
$this->user = $user;
}
public function build()
{
return $this->from('user#example.com')
->to($this->user->email)
->subject("Confirm your Email Address")
->view('emails.register.request')
->with("registration_token", $this->user->registration_token);
}
}
As you can see, I am using relational database to store jobs. And really, after calling LoginController's register method, a job is saved to database. But it can't be processed. I also start php artisan queue:work but nothing is done with jobs in database. Any help?
EDIT:
So I just found out that picking jobs from queue is done by SQL selecting the 'default' queue name. But I'm sending mails to queue 'emailsQueue'. So I'm now running Queue Worker like this: php artisan queue:work --queue=emailsQueue and everything's working fine for now. But how can I pick jobs from every queue in database? It's probably not the best attempt, right? It wouldn't make any sense to have named queues, right? But let's say I have one queue for processing register account requests, another queue for changing password requests and so on... So I think it does make sense to process every queue. So how can I do this? Can it be done just by listing the queues like this?
php artisan queue:work --queue=registerAccountEmailQueue,changePasswordEmailQueue...
What exactly does running php artisan queue:work? I thought it's the command to run all queues.
Use queue driver database.
In controller you should write
$this->dispatch(new SendNotifyMail($data));
This will pass your $data to queue. here SendNotifyMail is used as Job Class. So you should also use this in Controller like use App\Jobs\SendNotifyMail;.
Then create a file in Folder Jobs, named SendNotifyMail
<?php
namespace App\Jobs;
use App\Jobs\Job;
use DB;
use Mail;
use Artisan;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendNotifyMail extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
public $timeout = 300; // default is 60sec. You may overwrite like this
protected $data;
public function __construct($data)
{
$this->data = $data;
}
public function handle(Mailer $mailer)
{
$data = $this->data; // retrieve your passed data to variable
// your mail code here
}
}
In your command you need to write
php artisan queue:listen
or
php artisan queue:work
Then execute the code.
I have no problem sending synchronous mails, but the ones that get executed on a queue using Mail::queue throw the next error:
Illuminate\Contracts\Container\BindingResolutionException: Target [Swift_Transport] is not instantiable while building [Illuminate\Mail\Mailer, Swift_Mailer]. in /var/www/myapp.dev/vendor/illuminate/container/Container.php:804
Everything is configured correctly as emails are being sent when I do it synchronously
After having so much trouble with sending emails inside of Lumen Jobs, I encapsulated the email sending in a Job which works with mailables like this:
MailDispatcher.php
<?php
namespace App\Jobs;
use Illuminate\Contracts\Mail\Mailable;
use Illuminate\Support\Facades\Mail;
class MailDispatcher extends Job {
public $mail;
public function __construct(Mailable $mail) {
$this->mail = $mail;
}
public function handle() {
Mail::send($this->mail);
}
}
Then when I want to queue a mail...
$mail = new MyMailableMail($user);
dispatch(new MailDispatcher($mail));
And it works correctly
Well im testing this new notification stuff implemented in laravel 5.3 and its great,
i have this notification class which sends a mail to the authenticated user (when he hits a specific route) which is the default code.
notification
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class notifyme extends Notification implements ShouldQueue
{
use Queueable;
public function __construct()
{
//
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', 'https://laravel.com')
->line('Thank you for using our application!');
}
This is the controller functions that instantiates the notification class
public function notifyme()
{
$user = Auth::user()
$user->notify(new notifyme($user));
//$user->notify((new notifyme($user))->delay(Carbon::now()->addMinutes(10)));
return redirect('/home');
}
now while using a ubuntu os , and setting my queue driver as sync which should work fine on localhost QUEUE_DRIVER="sync"
i started a worker php artisan queue:work
But nothing shows on the terminal windows also page still a bit slow (queues are not working)
i have the default queue.php and i didnt change it, and as i mentioned, im using sync as a driver
Any suggested solution?
sync driver doesn't use queues, it allows to run jobs synchronously for running tests for examle.
You need to use one of the driver provided by laravel listed here - Laravel queues, or install some custom like RabbitMQ or something else