Laravel job calling class from nowhere? - php

I have a job in my Laravel project (v.4.2). which is used for inserting data into database. The class named "ProductUpdate". I use Amazon SQS for queue service.
What makes me confuse now is, when I changed the code in class "ProductUpdate",
it seems that the job is running by using old version of the class.
I even deleted all lines of code in the class but the jobs can still be able to run ( it stills inserts data).
Following is the job class.
The file of this class is at app/jobs/ProductUpdate.php
In my understanding, job class is the only place that will be called from queue, but why it can still be able to run when I deleted all the codes?
<?php
/**
* Here is a class to run a queued item sent from SQS
* Default method to use is fire()
**/
class ProductUpdate
{
public function fire($job, $data)
{
// Disable query log
DB::connection()->disableQueryLog();
// Set the job as a var so it will be used across functions
$this->job = $job;
$product = Product::find($productID);
if($product->product_type != 18) {
// Call the updater from library
$updater = App::make('Product\PriceUpdater');
$updater->update($product);
}
// Done and delete
$this->success();
}
private function success()
{
$this->job->delete();
}
private function fail($messages = array())
{
Log::error('Job processing fail', $messages);
$this->job->delete();
}
}

Your problem is related to cache.
Run this command in terminal to remove all cached data.
php artisan cache:clear
other way:-
Illuminate\Cache\FileStore has the function flush, so you can also use it:
Cache::flush();
This link will also help you :)

Related

Laravel 5.7 - Kill artisan after certain amount of time

I am developing a laravel 5.7 application.
I have created a command that should setup my database:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
class TestSetupCommand extends Command
{
protected $signature = 'test:data';
protected $description = 'Basic Setup for Test Data';
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
Artisan::call('migrate:refresh', ['--seed' => '']);
Artisan::call('basis:cc');
Artisan::call('tick:exchange');
$this->info("DB freshly setup: DONE");
$this->info("Coin: DONE");
$this->info("Exchange Scrapped: DONE");
}
}
My problem is that each command takes several minutes to run through. In total it costs me 25 minutes to fill the whole database with data.
I would like to run the commands only for 1 minutes each and kill them afterwards.
Any suggestions how to accomplish this within my laravel command?
I think the best way to do this is to extract these commands into background job. This artisan command then becomes code to queue up that new job (or jobs).
Why? It's very easy to configure jobs to timeout after x amount of time, by overriding a value like so:
<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* The number of seconds the job can run before timing out.
*
* #var int
*/
public $timeout = 120;
}
Also, why are you refreshing the database? That seems.... like a crazy idea unless this is purely an analytics platform (no user data at all). It's probably a bad thing if that refresh command times out - you may look into job chaining so that the refresh command is guaranteed to succeed, then the other commands (new jobs now) have set timeouts.

Laravel / PHP - Run 3 php functions in parallel

I have 3 functions that get json data from external apis and then saves in my database. Each function is its in own class e.g :
Class api1 {
public function fetch()
{
//Do Something
}
}
Class api2 {
public function fetch()
{
//Do Something
}
}
Since its api call might take some time or delay . I want to run all 3 in parallel so that api2 does not have to wait for api1 to complete.
Any way to do that ?
* Note : I'm also going to use laravel scheduler which will run each function every minute or run a single function containing all 3.
To me this looks more of like callback request for data, so to keep your app from not slowing down this should be a background job.
But before that I would implement an interface for those classes:
interface apiService{
public function fetch();
}
Class api1 implements apiService {
public function fetch()
{
//Do Something
}
}
Class api2 implements apiService{
public function fetch()
{
//Do Something
}
}
Create a job class php artisan make:job dataFetcher
Jobs will be structured under App\Jobs\
The job class in Laravel its dead simple, consisting of a constructor to Inject dependencies and handle() to fire the job.
protected $service;
public function __construct(apiService $service)
{
$this->service = $service;
}
public function handle()
{
$this->apiService->fetch();
}
Note that I am injecting the interface instead of concrete class, using a bit more high level code here. So now you can create a command to fire the calls with a cron job, or you can create a custom service provider to fire the commands as soon as app bootstraps.
I would go with a custom artisan command here:
So just create a custom artisan command on handle method
public function handle()
{
Job::dispatch(new FirstApiClass);
Job::dispatch(new SecondApiClass);
}
Handle method will execute first line and Job will be processed in background(doesnt matter if job failed or not), then next call will be fired and so on...
Note the use of the interface in this case, Job class doesnt really care which service you are calling as long as you provide an implmenetation of it.

Laravel Job deserialzation wrong class

I've got a problem while using Laravel's job Deserialization.
This is the Job class that is queued in the database:
class SendRatingEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $order, $user;
public function __construct(User $user, Order $order)
{
$this->order = $order;
$this->user = $user;
}
public function handle()
{
if ($this->order->isRatedByUser($this->user->id)) {
return;
}
Mail::to($this->user->email)->queue(new RatingEmail($this->order, $this->user));
}
}
In the class Order.php, I dispatch this job like this:
class Order {
function queueRating()
{
$when = Carbon::now()->addDays(env('ORDER_DAYS_RATING', 8));
dispatch((new SendRatingEmail($this->buyer, $this))->delay($when));
}
}
So the problem is in the job's handle() function, specifically the error is:
Call to undefined method Illuminate\Database\Query\Builder::isRatedByUser()
It seems as though Laravel gives me the wrong object, instead of App\Order it gives me the QueryBuilder. In the queueRating() function I have checked that the types given in the constructor are the expected types. I have even tested a workaround which also didn't seem to work:
if($this->order instanceof \Illuminate\Database\Query\Builder) {
$this->order = $this->order->first();
}
Also I have looked in the jobs table, and it seems as if the saved models are correct (App\Order)
Edit
Here is the code where the queueRating() function is called. The file is StripeController which handles credit card payments.
public function orderPaid($order) {
$order->payment_done = 1;
$order->save();
$order->chat->open = 1;
$order->chat->save();
$order->queueRating();
}
I found the problem, as always the problem is not where I looked. As it turns out, the code is completely fine, but I forgot to restart the queue worker on the staging server, which meant that changes in the code base were not applied in the queue worker. So the application and queue used different versions.
It is even stated in the Laravel Queue Documentation:
Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to restart your queue workers.
I use the bugtracker Bugsnag, which shows the error and also the line numbers in the code. I had noticed that the line number where the error occurred mismatched the real line number, but couldn't figure out that this was causing the problem.

Laravel 5: Running php artisan migrate, triggers functions in cron scheduler

So I have an interface I called iCron
namespace App\Console\CronScripts;
interface iCron{
public static function run($args);
}
I also have a class that uses this called UpdateStuff
class UpdateStuff implements iCron{
public static function run($args = NULL){
//I do api calls here to update my records
echo "Begin Updating Stuff";
}
}
So inside the Kernel I have:
use App\Console\CronScripts\UpdateStuff;
class Kernel extends ConsoleKernel{
protected $commands = [];
protected function schedule(Schedule $schedule){
$schedule->call(UpdateStuff::run(NULL))->dailyAt('23:00');
}
}
Which as it says I want to call the run function of UpdateStuff daily at 11PM. However the problem, is that it's calling the run function every time I use:
php artisan migrate
Anyone have any ideas why this is happening?
Thanks in advance!
EDIT: So I found where it's calling the schedule function,
vendor\laravel\framework\src\Illuminate\Foundation\Console\Kernel.php
This calls the defineConsoleSchedule() function which in-turn runs $this->schedule($schedule); Then for some reason, UpdateStuff::run($args) is executing even though It's not 11PM
I figured it out! So for anyone who is confused, the cron scheduler needs a Closure or a string that points to a static function with no parameters. Here's what I came up with:
class Kernel extends ConsoleKernel{
protected $commands = [];
protected function schedule(Schedule $schedule){
//This calls the run function, but with no parameters
$schedule->call("App\Console\CronScripts\UpdateStuff::run")->dailyAt('23:00');
//If you need parameters you can use something like this
$schedule->call(function(){
App\Console\CronScripts\UpdateStuff::run(['key' => 'value']);
})->dailyAt('23:00');
}
}
Hope This helps someone!

Laravel 5.1 No query results for model in queue

I am trying to learn laravel database queue from its official documentation. I have done configuration as given in documentation .
Here my jobs :
<?php
namespace App\Jobs;
use App\SearchLog;
use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendTicket extends Job implements SelfHandling, ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $log;
protected $searchLog = array();
public function __construct(SearchLog $log , $data = array())
{
$this->log = $log;
$this->searchLog = $data;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$this->log->create($this->searchLog);
}
In my controller I call like this
public function store(Request $request)
{
$searchLog = array();
// searchLog contains the data to be inserted into database
$log = new SearchLog();
$this->dispatch(new SendTicket($log , $searchLog));
}
When I run the php artisan queue:listen I get the error like
[Illuminate\Database\Eloquent\ModelNotFoundException] No query
results for model [App\SearchLog].
But when I edit the jobs like this
//only edited code
public function __construct($data = array())
{
$this->searchLog = $data;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
SearchLog::create($this->searchLog);
}
And when call from like this
public function store(Request $request)
{
$searchLog = array();
// searchLog contains the data to be inserted into database
$this->dispatch(new SendTicket($searchLog));
}
It works fine and the data is inserted .
Here, my question is :
How to send the object to the queue ?
What is best way to send data to queue so that we can process ?
The problem is in the use Illuminate\Queue\SerializesModels;, which tries to serialize the SearchLog $log param which you're passing to the constructor. Since your model is not saved yet, it doesn't have the identifier.
According to Laravel documentation:
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.
The workaround would be to remove SerializesModels trait from the Job class you're willing to save your model in.
I ran into the same issue.
It seems if you want to push an Model to the queue only its ID will be saved in the payload. So if you haven't saved the Model yet, it wont be available in the handler.
After all I found it in the documentation in the section Queues and Eloquent Models.
To solve this issue I see two solutions, the first is to make sure you have a persistent Model:
public function store(Request $request)
{
$searchLog = array();
// searchLog contains the data to be inserted into database
$log = new SearchLog();
//Save the Searchlog beforehand if it doesn't have any data constraints
$log->save();
//Dispatch the Job with the saved Model
$this->dispatch(new SendTicket($log , $searchLog));
}
or put the full Model Saving process to the handler only, like you did in your example.
//Full saving/initializing is happening here
public function handle()
{
SearchLog::create($this->searchLog);
}
In my case I had to save the Model to a database in a high performance process, so i put it fully in the handler that my process wasn't dependent on the db saving speed. So i would put it in the handle() function.
This issue is usually raised if the Model is not saved or persisted yet. Check your model instance and persistance. Another thing may raise this issue is Multi-Tenancy. So if you are using or building a Multi Tenant application with Multi Databases, you may need to figure out a way to pass the database connection to the queue or just use arrays of data as stated by Tylor Otwell here [5.4] Support queued jobs with unpersisted models

Categories