My application is hosted on a shared hosting platform that limits to 200 emails per hour.
My application is running database connection driver and I have 3000 jobs in the jobs table.
I would like to throttle this queue to only send 1 email every 30 secs or 1 minute to ensure I don't run issues with my hosting.
Research:
I have tried delay from this tutorial, rate limiting from this question with no response, delayed jobs from this laravel documention but nothing works.
Question: Is there a way to throttle the queue in database queue connection like they do it in redis queue connection i.e
// Allow only 1 email every 30 seconds
Redis::throttle('any_key')->allow(1)->every(30)->then(function () {
Mail::to($this->email)->send(new NotificationEmail($this->data) );
Log::info('Emailed order ' . $this->email);
}, function () {
// Could not obtain lock; this job will be re-queued
return $this->release(2);
});
My implementation: Delays only for the first job then sends the others with no delay
public function sendEmailNotification($email,$data)
{
//Send email to user and to admin
$email_job = (new ProcessEmailNotificationJob($email,$data))->delay(now()->addSeconds(30));
if($this->dispatch($email_job)){
return true;
}
else{
return false;
}
}
**ENV File: **
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=database
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
CodePudding user response:
did you run php artisan queue:listen, if yes check my below code maybe it will help
inside your controller:
$mail = (
[
'data' => $EmailData,
'userName' => $userData->first_name,
'userMail' => $userData->email,
'subject' => $subject
]);
SendMailJob::dispatch($mail)
->delay(now()->addSeconds($waitSec));
$waitSec = 30; //seconds interval
SendMailJob class
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 App\Mail\ClientRegistrationNotification;
use Mail;
class SendMailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $bulkMail, $mail;
public function __construct($Mail)
{
$this->mail=$Mail;
}
public function handle()
{
try {
Mail::to($this->mail['userMail'])
->queue(new ClientRegistrationNotification($this->mail['data'], $this->mail['userName'], $this->mail['userMail'], $this->mail['subject']));
} catch (\Throwable $exception) {
$this->fail();
}
}
}
CodePudding user response:
I'm not sure if this is the best option but the only solution that worked for me was sleeping the queue for 30 seconds after dispatch i.e
Dispatch Method
public function sendEmailNotification($email,$data)
{
//Dispatch all 3000 with no delay
if(ProcessEmailNotificationJob::dispatch($email,$data)){
return true;
}
else{
return false;
}
}
Sleep Queue Sender
class ProcessEmailNotificationJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $email;
private $data;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($email,$data)
{
//
$this->email = $email;
$this->data = $data;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
//Send the Mail and sleep for 30 Seconds before sending the next one
sleep(30);
Mail::to($this->email)->send(new NotificationEmail($this->data) );
}
}