For some reason whenever I run
Mail::to($user)->queue(new WelcomeEmail($user))
it sends immediately instead of queuing it. I've already followed the Driver Prerequsites.
I tried to run it on artisan tinker and it still doesn't add to the queue.
This is my WelcomeEmail class:
<?php
namespace App\Mail\User;
use Illuminate\Bus\Queueable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use App\Modules\User\User;
class WelcomeEmail extends Mailable
{
use Queueable, SerializesModels;
/**
* #var Model
*/
public $user;
/**
* Create a new message instance.
* #param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('emails.user.registered');
}
}
Is it because I'm running on a Windows machine?
Based on your comment in the question, the trouble is that you have your queue_driver set to SYNC in your .env file. This "driver" will process everything immediately, this is useful when developping.
You need to set it to "database" if you want to use the database driver, or "redis" for the redis driver.
Related
I am implementing Queue JOBS, in my Laravel Project for the first time. But I am facing some difficulties on it, as after php artisan queue:work, noting is showing on the terminal.
Let Me describe, the procedure I have tried.
My Controller Function, from where I am trying to fire the Job Queue:
use App\Jobs\InitiateRecharge;
/
/*** Other Codes are here....
/
public function testQueueJob(){
InitiateRecharge::dispatch(1)->onQueue('initrecharge');
return 1;
}
My JOB Queue Class:
<?php
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;
class InitiateRecharge implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $reportid;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($reportid)
{
$this->reportid = $reportid;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
sleep(10);
\Log::info('hello....');
}
}
I have also migrated the jobs table, and rows are also getting inserted on that.
It's is not giving any error, but the Job expected output is also not coming .. and in the terminal noting getting changed.
Please, anyone, help me
Thank You in advance :)
try php artisan queue:listen --tries=1
In my multi-server application I use laravel's Queueing system in order to run background jobs. Sometimes in my logic I want to make my job to throw an exception so I can log it via a sentry using the laravel library that offers.
So in my job:
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use App\Model\Etable\User;
use App\Model\User;
class MyJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
/**
* #var int
*/
private $user_id;
/**
* #param int $user The user that has opted or deopted for newsletter consent
*/
public function __construct(int $id)
{
$this->user_id = $user_id;
}
public function handle(): void
{
/**
* #var User
*/
$user=User::useWritePdo()->find($this->user_id);
if(empty($user)){
throw new \Exception("No such a user with user id: {$this->user_id}");
}
// Rest of logic here
}
}
Once the exception is thrown, I will to be logged into sentry but also it will keep on respawning as laravel's logic for jobs is supposed to do so.
In my case I think it as waste of resources to keep an respawning the MyJob in case that the user does not exist no value to keep on spawning because the logic itself cannot be performed in case that no user exists. On the other hand on any other error I want my job to keep on retrying till be able to sucessfully run again.
So how I can make my job not to respawn on specific errors? Even better would be as well if I can use the default logging method that laravel ofers in order to arbitary log an error into sentry as well via a sentry dedicated channel.
The best and easier approach is once the code failt to check how many times has already be executed:
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use App\Model\Etable\User;
use App\Model\User;
class MyJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
/**
* #var int
*/
private $user_id;
/**
* #param int $user The user that has opted or deopted for newsletter consent
*/
public function __construct(int $id)
{
$this->user_id = $user_id;
}
public function handle(): void
{
/**
* #var User
*/
$user=User::useWritePdo()->find($this->user_id);
if(empty($user)){
if ($this->attempts() > 1) {
return;
}
throw new \Exception("No such a user with user id: {$this->user_id}");
}
// Rest of logic here
}
}
This is being achieved via the:
if ($this->attempts() > 1) {
return;
}
So you throw once the exception, the exception is being logged into the Sentry and then on the second time that will be executed it will just exit and never respawn.
Please note that failed jobs won't be re-run unless you explicitly run
php artisan queue:failed
You can throw an exception and handle it in boot method of AppServiceProvider, deleting the job to avoid its further re-tries. See documentation on how to do it.
This is the complete error.
Illuminate\Mail\SendQueuedMailable::handle(): The script tried to
execute a method or access a property of an incomplete object. Please
ensure that the class definition "Security\Mail\WelcomeMail" of the
object you are trying to operate on was loaded before unserialize()
gets called or provide an autoloader to load the class definition in
/var/www/html/vendor/laravel/framework/src/Illuminate/Mail/SendQueuedMailable.php
We are using Laravel 5.5. And executing the following code
Mail::to($customer)->queue(new WelcomeMail($customer));
The mailer is the default mailer that comes with laravel, but we're queueing jobs to redis. Customer is a User object. The WelcomeMail is the following
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class WelcomeMail extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
public $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('security::emails.welcome');
}
}
I figured out what was my problem. It was more than one server (localhost, staging etc... ) had a queue listener on the same Redis instance.
I use spatie media library for one of my project. requirement is when uploaded image status is approved then generate conversions of that particular image. So, i write code for that in My Model is:
public function registerMediaConversions(Media $media = null)
{
$listingStatus = ListingStatus::where('type', Listing::ITEM_TYPE_PHOTOS)->where('item_id', $media->id)->where('status', self::STATUS_APPROVED)->whereNotNull('review_by')->first();
if ($listingStatus)
$this->registerBaseConversions(true);
}
and when image getting approved then i dispatch job for run command.
$this->dispatch(new GenerateMediaCollection($mediaId));
Job:
<?php
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 Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
class GenerateMediaCollection implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $mediaId;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($mediaId)
{
$this->mediaId = $mediaId;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Log::info('generate Media collection');
exec('php artisan medialibrary:regenerate --ids='.$this->mediaId);
}
}
so, in Local all is working perfectly but in server, job is processed but conversions not added.
if i run command in server from terminal then it is working.
So, what i have to do for this issue?
TIA.
Try adding --force to arguments. I.e. make it
exec('php artisan medialibrary:regenerate --ids='.$this->mediaId --force')
I'm using database driver to queue my jobs.
I need to call an artisan command from a queued Job and when the Job has finished I need to remove it from the queue.
This is my controller's code where I add the job in the queue
dispatch((new SendNewsletter())->onQueue('newsletter'));
This is my queued Job
<?php
namespace App\Jobs;
use App\Console\Commands\Newsletter;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class SendNewsletter implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
app()->make(Newsletter::class)->handle();
}
}
The artisan command I need to call is App\Console\Commands\Newsletter
and when the Job ends, this should remove it from the queue.
This is AppServiceProvider class
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot() {
Queue::after(function ($event) {
if ($event->job->queue == 'newsletter') {
$event->job->delete();
}
});
}
The Job is added correctly to the database queue and when I run php artisan queue:work the job is called multiple times endless.
seems that Queue::after's callback is never called.
any idea what am I missing ?
Probably your job fails and it is added to queue trying to finsh the work correctly. Try calling the command in your job like this
\Artisan::call('your:command');
Instead of:
app()->make(Newsletter::class)->handle();
Where "your:command" is the command name, that you gave in the command class:
protected $signature = 'email:send {user}';