Why handle method does not fire during job execution? - laravel

I have always used events and listeners to add tasks to the queue. Now I'm trying to use Jobs. I do it like this:
my job.
class eventJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $message;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($message)
{
$this->message = $message;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Log::alert($this->message);
}
}
My .env file: QUEUE_CONNECTION=database
In my controller, I dispatch the event like this:
eventJob::dispatch('my message');
A new record appears in the jobs table and to execute it I run php artisan queue:work
The record is removed from the jobs table, but nothing appears in the file logs
I tried in the handle method and the constructor to do throw new \Exception("Error Processing the job", 1); But nothing is written in the filed_jobs table, from which I made the assumption that the handle method and the constructor do not execute.
I also tried running my job like this:
$job = new eventJob('my test message'); dispatch($job);
But it does not change anything

I don't know why but when I changed config/queue.php file from 'default' => env('QUEUE_CONNECTION', 'sync') to 'default' => env('QUEUE_CONNECTION', 'database') everything started working as it should

Related

laravel supervizor queue MaxAttemptsExceededException

I have a Laravel application and I use files with supervisor.
When I launch a job I have the following error after 60 seconds.
I have increased this delay everywhere but the timeout remains at 60 seconds.
Do you know how to increase the timeout of a job please?
I use the database connector (I also tried with redis) but it's the same
Thank you.
class BuildAvailabilities implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $timeout = 600;
protected $userId;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($userId)
{
$this->onQueue('availabilities');
$this->userId = $userId;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$availabilityService = app(AvailabilityBuilderService::class);
$availabilityService->updateAvailabilities($this->userId);
}
/**
* Get the middleware the job should pass through.
*
* #return array
*/
public function middleware()
{
return [(new WithoutOverlapping($this->userId))->dontRelease()];
}
}
In horizon.php under your's connection try to specify the 'timeout' property to higher value and increase also the 'tries' property of your connection. But the main problem for us is that our's jobs are just too unoptimized and runs too long.
Also you can also specify public $maxExceptions = 3; in job.
Tell me when you find a solution
And check this: https://github.com/laravel/horizon/issues/255

How to delay Laravel Job Queue

I am trying to learn about Jobs and queues in Laravel , when i try to learn something new i always take a basic example by myself and try to understand the workflow better.
Okay here is the problem
I have created a Job in Laravel as you can see in the handle method i am just trying to print a simple message on the laravel.logger , this works totally fine.
class SendEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $email;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($email)
{
$this->email = $email;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Log::info($this->email . '<<<<<<<<<<<<<<<');
}
}
My problem is that i want to delay this job for 2 minutes then to dispatch it ,
i have tried it this way but without success both logs are printed immediately when index method is being called but i want $job = new SendEmailJob("This will show after 2 minutes"); to be called after 2 minutes an not printed immediately
public function index(){
$on = Carbon::now()->addMinutes(2);
Log::info('Test');
$job = new SendEmailJob("This will show after 2 minutes");
$job->delay($on);
dispatch($job);
return "none";
}
You can take a look at the documentation: https://laravel.com/docs/8.x/queues#delayed-dispatching
You can do following: (new SendEmailJob("This will show after 2 minutes"))->delay(now()->addMinutes(2)); or
SendEmailJob::dispatch("This will show after 2 minutes")->delay(now()->addMinutes(2));

Put function in Queue but not loaded relation data | Laravel Queue

I need to generate a pdf of user with their related data. I have created a function in controller to generate pdf(using snappy-pdf package). Data is loaded properly, pdf generated and uploaded on S3 successfully. Now I am trying to put that function in queue with user data. But data is not loaded for generation pdf. Instead it only laod the user model data but not the related data (like property and contact).
$user = User::where("id", 83)->with(['property', 'contacts'])->first();
$contact_list = [];
if(count($user->contacts)){
foreach ($user->contacts as $contact) {
array_push($contact_list, $contact->contactDetails->name);
}
}
$user->contact_list = $contact_list;
return view('pdf_view', ["user" => $user]);
if($request->has('download')) {
// dispatch the event
/*$pdf = PDF::loadView('pdf_view', ["user" => $user]);
// upload pdf
Storage::disk('s3')->put("user-invoice/user.pdf", $pdf->output(), 'public');*/
dispatch(new GenerateSignedDocument($user));
return "done";
}
And here is my job file.
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Log;
use PDF;
use Storage;
class GenerateSignedDocument implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
private $user;
public function __construct($user)
{
$this->user = $user;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
// Log::info('Showing user: '.$this->user);
$pdf = PDF::loadView('pdf_view', ["user" => $this->user]);
// upload pdf
Storage::disk('s3')->put("user-invoice/user.pdf", $pdf->output(), 'public');
}
}
The SerializesModels trait only stores the model's key and reloads the model from the database when it is unserialized, so this is likely not going to load your relationships.
This is usually a big benefit as you'll receive fresh data when your queued job actually runs, not the data from when the job was scheduled.
In any case, it's probably best to either:
Load the relationships the job requires in the job itself and not rely on them being preloaded.
or
Pass the property and contacts as separate dependencies to your job class.
I don't know this is the perfect solution or not but I do this and work fine.
I called the required function(uploadUserDocument) for performing pdf generation in the handler function.
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
app('App\Http\Controllers\UserController')->uploadUserDocument($this->user_id);
}
and dispatch the event as it is in the controller
dispatch(new GenerateSignedDocument(83));
and put the required code for generating pdf in the uploadUserDocument function like this.
/**
* Function is used to Save document to s3 cloud
* #param $user_id
* #return Response
*/
public function uploadUserDocument($user_id){
$pdf = PDF::loadView('pdf_view', ["user" => $user]);
// upload pdf
Storage::disk('s3')->put("user-invoice/user.pdf", $pdf->output(), 'public');
}

Laravel 5.4 saving models via async queue

So I am trying to optimize my site and on every page load and exit I save a metric (time on page, ip address etc) for analytics. However these are decent sized bottlenecks on my server. When viewing the time it takes for things to run my entire function takes ~1-2ms and then saving to the DB takes ~100-200ms. So my goal is to run my function and then dispatch a new job, that will do the actual saving of the metric. This way all of the saving of my models can be offloaded to a queue. Below is a copy of my job
class SaveMetric 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(Metrics $metric)
{
//
$metric->save();
}
}
Then in my controller function after I grab all the values I need I run this
dispatch(new SaveMetric($newMetric));
This seems to run but does not seem to do anything. Am I missing something? (Edit) This does ~something~ it just saves a record to the DB with null in all the fields, as if I created a new metric without any values.
Is it required to pass a queue into the job dispatch?
Do I need to run a daemon or something similar to actually process the things in the queue?
I created the job using the artisan make:job command
You're pretty close.
class SaveMetric implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $metric;
/**
* Create a new job instance.
*
* #param Metrics $metric
*/
public function __construct(Metrics $metric)
{
$this->metric = $metric;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$this->metric->save();
}
}
According to the docs:
In this example, note that we were able to pass an Eloquent model directly into the queued job's constructor. Because of the SerializesModels trait that the job is using, Eloquent models will be gracefully serialized and unserialized when the job is processing. If your queued job accepts an Eloquent model in its constructor, only the identifier for the model will be serialized onto the queue. When the job is actually handled, the queue system will automatically re-retrieve the full model instance from the database.

Laravel 5 - Queued Commands throwing spl_autoload_call() error

UPDATE - This has been narrowed down to beanstalkd, sync works
I am receiving the following error when attempting to run queued commands in my production environment:
exception 'ErrorException' with message 'unserialize(): Function spl_autoload_call() hasn't defined the class it was called for'
in /home/forge/default/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php:74
I have tried both the beanstalkd and database drivers, no change. For simplicity, I am using the following command:
<?php namespace App\Commands;
use App\Commands\Command;
use App\User;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldBeQueued;
class TestQueueCommand extends Command implements SelfHandling, ShouldBeQueued {
use InteractsWithQueue, SerializesModels;
/**
* #var User
*/
private $user;
/**
* Create a new command instance.
*
* #param User $user
*/
public function __construct(User $user)
{
//
$this->user = $user;
}
/**
* Execute the command.
*
* #return void
*/
public function handle()
{
\Log::info("You gave me " . $this->user->fullName());
}
}
Dispatch code:
get('queue-test', function()
{
Bus::dispatch(new TestQueueCommand(User::first()));
});
This works in my Homestead environment, fails in production (Digital Ocean, Forge). I have several beanstalkd workers and I have tried restarting them. I have also run php artisan queue:flush.
Here is the code where the error is occurring (from source):
/**
* Handle the queued job.
*
* #param \Illuminate\Contracts\Queue\Job $job
* #param array $data
* #return void
*/
public function call(Job $job, array $data)
{
$command = $this->setJobInstanceIfNecessary(
$job, unserialize($data['command'])
);
$this->dispatcher->dispatchNow($command, function($handler) use ($job)
{
$this->setJobInstanceIfNecessary($job, $handler);
});
if ( ! $job->isDeletedOrReleased())
{
$job->delete();
}
}
In the past, I also ran into a similar issue while unserializing. The problem was the default Beanstalk job size (65,535 bytes), which might not be big enough if the class being serialized contains lots of properties that need to be kept (increasing the size of the serialized string and using more than 65K for storage).
In order to solve this, try setting the size to 131,072 or even 262,144 bytes using the -z option, on the configuration file (/etc/default/beanstalkd):
BEANSTALKD_EXTRA="-z 262144"
After that, you should restart the service.
Also note that the configuration file path might be other, depending on the distribution you're using.
And since you're using Digital Ocean, you might find their documentation useful.

Resources