Why queue still waiting when send mail in laravel? - laravel

i want send mail in queue and have not waiting when send mail
https://laravel.com/docs/5.7/queues#connections-vs-queues
i run command to create table jobs:
php artisan queue:table
php artisan migrate
I create a job to send mail: php artisan make:job SendEmailJob
and edit code :
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Mail;
class SendEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public $body;
public $emailto;
public function __construct($body,$email)
{
//
$this->body=$body;
$this->emailto=$email;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$email=$this->emailto;
Mail::send("body_email.confirm_order",['Body'=> $this->body], function($message) use ($email)
{
$message->from(env('MAIL_USERNAME'),"Eye glasses");
$message->subject("Confirm Email");
$message->to($email);
});
}
}
I call queue from controller:
use App\Jobs\SendEmailJob;
public function index()
{
$Body="test";
$email="daitb#vnitsolutions.com";
SendEmailJob::dispatch($Body, $email);
$calendars= AppointmentModel::GetAppointmentofDoctor($id,$datetime);
return view('frontend.appointment',["calendars"=>$calendars]);
}
add QUEUE_DRIVER=database to file .env
run command:
php artisan queue:work
If i run controller, process still waiting send mail finish and run other process.
i try change to:
SendEmailJob::dispatch($Body, $email)->delay(now()->addMinutes(3));
It not delay,it still send mail after 5s.
Why queue still waiting when send mail in laravel?
I using win 32.

My Problem fixed by change QUEUE_CONNECTION=sync to QUEUE_CONNECTION=database in .env file

Related

Send large number of notifications to users - Laravel

I want to send a large number of notifications in Laravel.
The notification method is firebase and I'm using kutia-software-company/larafirebase package as Notifiable.
Currently, I have about 10000 fcms but I want to optimize sending notifications to 100000 fcms.
I implemented a system like below:
First, I created a notifiable class as described in the package
<?php
namespace Vendor\Core\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Kutia\Larafirebase\Messages\FirebaseMessage;
class FirebasePushNotification extends Notification
{
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(protected $title, protected $message, protected array $fcmTokens = [])
{
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['firebase'];
}
public function toFirebase($notifiable)
{
return (new FirebaseMessage)
->withTitle($this->title)
->withBody($this->message)
->withPriority('high')
->asNotification($this->fcmTokens);
}
}
Second, Created a Job for notifications:
<?php
namespace Vendor\PushNotification\Jobs;
use Vendor\Core\Notifications\FirebasePushNotification;
use Vendor\Customer\Contracts\UserDeviceInfo;
use Vendor\Customer\Contracts\Customer;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Notification;
class SendPushNotificationJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Batchable;
public function __construct(public string $title, public string $body, public Customer $customer, public UserDeviceInfo $userDeviceInfo)
{
}
public function handle()
{
Notification::send($this->customer, new FirebasePushNotification($this->title, $this->body, [$this->userDeviceInfo->fcm]));
}
}
And using Bus::dispatch for sending jobs to queue:
$usersDeviceInfos = $usersDeviceInfos->with('customer')->get();
$bus = [];
for ($i = 0; $i < 100000; $i++){
foreach ($usersDeviceInfos as $usersDeviceInfo) {
$bus [] = new SendPushNotificationJob($data['notification_title'], $data['notification_body'], $usersDeviceInfo->customer, $usersDeviceInfo);
}
}
Bus::batch($bus)->name('push notification' . now()->toString())->dispatch();
Currenly, because of development environement I have just one fcm and use a loop to simulate 10000, It takes more than a minute to run this code and I'll get Maximum execution error.
Also, note that I configured my queue and it's not sync and I checked these two questions but didn't help:
fastest way to send notification to all user laravel
Laravel: Send notification to 1000+ users [closed]
Hope to find a faster method to batch those jobs and send them to queue
I found a solution that can handle sending notifications up to one million fcms in a few seconds
I decided to use kreait/laravel-firebase and use multicast that was mentioned here
First I chunk fcms then I use A job and dispatch them to the queue.
Here's an example of the solution:
<?php
namespace Vendor\PushNotification\Jobs;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Kreait\Firebase\Messaging\CloudMessage;
use Kreait\Laravel\Firebase\Facades\Firebase;
class SendPushNotificationJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Batchable;
public function __construct(public string $title, public string $body, public array $fcmTokens)
{
}
public function handle()
{
$message = CloudMessage::fromArray(YOUR_DATA);
Firebase::messaging()->sendMulticast($message, $this->fcmTokens);
}
}
$chunks = $usersDeviceInfos->with('customer')->get()->pluck('fcm')->chunk(500);
foreach ($chunks as $chunk) {
dispatch(new SendPushNotificationJob($data['notification_title'], $data['notification_body'], $chunk->toArray()));
}

How to solve Laravel Pusher Error data content of this event exceeds

I did the update to Laravel 9 today. Before, Pusher worked well on the application.
Now, I receive always the following error:
Pusher error: The data content of this event exceeds the allowed maximum (10240 bytes)
I didn't change the content.
I tested to change the content with the given supplier_id, with a fake id like "ee" and without any restrictions.
In the console log, I have the following result:
Why does pusher work, even there is an error in the backend?
<?php
namespace App\Events\Kanban;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class KanbanOrderCreatedEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $kanbanOrder;
public function __construct($kanbanOrder)
{
$this->kanbanOrder = $kanbanOrder;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return ['kanbanOrders.'.$this->kanbanOrder->network_supplier_id];
}
public function broadcastAs()
{
return 'kanbanOrderCreated';
}
public function broadcastWith()
{
return ['supplier_id' => $this->kanbanOrder->network_supplier_id];
}
}

Laravel 7 | Some recipients receive empty emails

I have an laravel 7 application and use smtp with google services to send my emails.
However some clients receive the emails with attachments, but no body. The content of the email is completely blank. Most mail platforms (hotmail, outlook, gmail, mail on mac) receive the complete email. It's just some mail providers receive the email without a body.
I believe this might have to do with some security measures or not supporting HTML emails.
How can I ensure that also these clients receive my emails?
I use .blade.php files to send my emails.
example of one of my email files:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class CandidateMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($message_details)
{
//
$this->message_details = $message_details;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$email = $this->view('mail/candidate')
->subject($this->message_details['subject'])
->with(['message_details' => $this->message_details]);
if ($this->message_details['attachments']) {
$email->attachFromStorage($this->message_details['attachments']);
}
return $email;
}
}
Fix for outlook (desktop).
replaced my divs with table/tr/td. Now email content is displayed to clients with outlook (desktop).
you had to build your constructor the variable $message_details does not return anything,
public $message_details = "";
Need to declare public property public $message_details here details
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class CandidateMail extends Mailable
{
use Queueable, SerializesModels;
public $message_details;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($message_details)
{
//
$this->message_details = $message_details;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$email = $this->view('mail/candidate')
->subject($this->message_details['subject'])
->with(['message_details' => $this->message_details]);
if ($this->message_details['attachments']) {
$email->attachFromStorage($this->message_details['attachments']);
}
return $email;
}
}

Queues are executed instantly without delay

i am using postgresql as db, in .env i have set QUEUE_CONNECTION = database
I download from url, for example, a picture and transfer it to the queue for uploading in storage laravel
In web.php, I registered a route to the queue
Route::get('/job', function () {
App\Jobs\FileAdd::dispatch("https://www.example.com/example.jpg")->delay(now()->addMinute(25));
});
In job, I wrote the following:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
class FileAdd implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $File;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($File)
{
$this->File = $File;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
info($data = $this->File);
$pos = strripos($data, '/');
$link = substr($data, 0 , $pos+1);
$filename = substr($data, $pos+1);
$expansion = substr($filename, -4);
$tempImageTwink = tempnam('..\storage\app\public', $filename);
$tempImage = substr($tempImageTwink, 0, -4) . $expansion;
copy($link . '/' . $filename, $tempImage);
Storage::delete('exa3BBD.tmp');
response()->download($tempImage, $filename);
unlink(($tempImageTwink ));
}
}
in the database I have two tables jobs, failed_jobs, for writing queues, but they are executed immediately without delay, what could be the problem?
Might be problem with cache if you just change it in .env file. Laravel cache your .env file and look at the cache if it is available not the .env file itself. So changes is not active, unless you will clear you cache or create new one. Try clear your cache with:
php artisan optimize:clear
or
php artisan cache:clear
so new data from .env file can be loaded.

Keep PHPMailler connection alive over Laravel's queue

I want to send many emails.
Currently I write basic code use PHPMailler to send mail using queue. It works, but everytime new queue is run, it have to connect to SMTP again, so i get bad perfomance.
I find SMTPKeepAlive property on PHPMailler documentation:
$phpMailer = New PHPMailer();
$phpMailer->SMTPKeepAlive = true;
Is it imposible and how to keep $phpMailler object for next queue? So PHPMailler have not to connect again by using previous connection.
If you are using Laravel then you have to use Laravel's feature inbuilt.
Please find below documents:
https://laravel.com/docs/5.6/mail
Please find a piece of code for send mail and adding in a queue:
use App\Mail\EmailVerifyMail;
\Mail::queue(new EmailVerifyMail($users));
EmailVerifyMail.php
<?php
namespace App\Mail;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class EmailVerifyMail extends Mailable
{
use Queueable, SerializesModels;
public $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$this->to($this->user)->subject(__('mail.subjects.verification_link', ['USERNAME' => $this->user->name]));
return $this->view('mails/emailVerify', ['user' => $this->user]);
}
}

Resources