Queueing mails in Laravel - php

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.

Related

how to run the jobs queue immediately after a job added to queue in laravel?

I currently registered php artisan schedule:run in cronjob in cpanel and the schedule method is:
protected function schedule(Schedule $schedule)
{
$schedule->command('queue:work --stop-when-empty')
->cron('* * * * *')
->withoutOverlapping(5);
}
But for my purpose it is necessary to run the jobs immediately,
How can I run php artisan queue:work immediately after a job added to queue(jobs table) and not after one minute?
For Laravel > 7.x We can dispatch anonymosly
use App\Mail\WelcomeMessage;
use Illuminate\Support\Facades\Mail;
dispatch(function () {
Mail::to('taylor#laravel.com')->send(new WelcomeMessage);
})->afterResponse();
The WelcomeMessage should implement/use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
For Laravel 6.x
Instead of dispatching a job class to the queue, you may also dispatch a Closure. This is great for quick, simple tasks that need to be executed outside of the current request cycle:
$podcast = App\Podcast::find(1);
dispatch(function () use ($podcast) {
$podcast->publish();
});
for more you can read laravel docs https://laravel.com/docs/7.x/queues
the solution is to call queue:work on destruct() method of each class that I want to run it's job immediately.
use Illuminate\Support\Facades\Artisan;
class ProductShopObserver implements ShouldQueue
{
public function __destruct()
{
Artisan::call('queue:work --stop-when-empty');
}
}

add job to queue Laravel

i got a problem when execute my queue. Job doesnt work.
.env:
QUEUE_CONNECTION=database_name
Job:
use App\Models\ProfessorSuscriptionHistory;
class CheckSuscription implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct()
{
}
public function handle()
{
$suscription_history = new ProfessorSuscriptionHistory();
$suscription_history->user_id = 13;
$suscription_history->type = 'trimestral';
$suscription_history->pdf = 'test.pdf';
$suscription_history->ended_at = Carbon::now()->addMonth(3);
$suscription_history->save();
}
}
My controller what dispatch a Job
use App\Jobs\CheckSuscription;
class TestController extends Controller
{
public function index()
{
CheckSuscription::dispatch()->onQueue('processing');
}
}
i used command php artisan queue:work and php artisan queue:listen but nothing appear in cmd. i migrated jobs to my db using php artisan queue:table and nothing appear in jobs table or failed_jobs table too. How can i fix that? thx!!
Put your QUEUE_CONNECTION=database_name to just QUEUE_CONNECTION=database you dont put the database name you just tell Laravel to use a certain queue. database, redis ...
Queue Connection

Lumen prevent duplicate job in a queue

Using lumen 8.2.3 I am only trying to dispatch a unique job to a queue. In app/Console/Kernel I have sent a schedule to $schedule->job(new myJob(), 'high')->everyMinute(); this runs every minutes.
In the job itself I have added the ShouldBeUnique interface class in myJob class I even added
public function uniqueId() {
return $this->process->id();
}
when my cron job runs for php artisan schedule:run, this is still creating multiple jobs in the queue causing my 3 workers to pick up both jobs at the same time and causing issues.
https://laravel.com/docs/8.x/queues#unique-jobs clearly says
"Sometimes, you may want to ensure that only one instance of a
specific job is on the queue at any point in time. You may do so by
implementing the ShouldBeUnique interface on your job class. This
interface does not require you to define any additional methods on
your class:"
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Throwable;
class myJob implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue, Queueable, SerializesModels;
private $process;
public function __construct($process){
$this->process=$process;
}
public function uniqueId() {
return $this->process->id();
}
public function handle()
{
//some code here
}
public function failed(Throwable $exception)
{
// Send user notification of failure, etc...
}
}
Is the no way to prevent this? thank you
The code provided barely reflects what you are writing; there's no job at all.
The declaration should look like this:
class SomeJob implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue, Queueable, Dispatchable;
...
}
odd how this got fixed but what I did was change the version from 8.2.4 to 8.3.4 and shouldBeUnique work looks like a bug was introduced in 8.3.4

Laravel Jobs and Queues not working as expected

I'm creating an application which generates a video. This is a quite intensive function and takes a few minutes to generate. So I want to create a async process for this. After some research I've read about Jobs and Queues in Laravel.
But now my jobs don't get inserted in the jobs table. I can't find out what I've done wrong.
My function which starts the job:
public function generate() {
$id = Auth::user()->id;
GenerateJob::dispatch($id);
}
My Job
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Auth;
class GenerateJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct($dossierId)
{
$this->dossierId = $dossierId;
}
public function handle()
{
sleep(5);
}
}
.ENV QUEUE_DRIVER=database
I did run php artisan clear:config but nothing seems to help.
Nothing I try seems to work. The jobs table remains empty and the job is executed synchronously instead of asynchronously. What am I missing here?
After hours of debugging I finally found a solution to my problem. Adding ->onConnection('database'); to GenerateJob::dispatch($dossier_id); solved it all..
I wish I could say why this was necessary, but I have no clue since I already put that in my .env file. Hope this helps for someone else in this situation. :-)

Laravel queue stalls when used with sentry

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.

Categories