Laravel Cron Scheduler job not running as expected - php

I have Laravel cron issue ,In Console Kernel I have defined job which will hit Rollovercron.php file every 10 mins and every time it will hit it will pass one country. atleast 100 Countries are defined in an array and will be passed one by one to Rollovercron.php according to foreach loop. Rollovercron.php file takes minimum 2 hrs to run for single country.
I have multiple issues with this cron job:
100 elements in an array not getting fetched one by one means I can see 'GH' country(Ghana) has run for 5 times continuously and many of the countries are skipped.
when ever I get country missing issue I do composer update and clear cache frequently.
I want my cron should run smoothly and fetch all countries not even single country should miss and I should not need to do composer update for this all the time.
Please help me in this ,struggling for this since many months.
bellow is Kernel.php file:
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use DB;
class Kernel
extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
\App\Console\Commands\preAlert::class,
\App\Console\Commands\blCron::class,
\App\Console\Commands\mainRollover::class,
\App\Console\Commands\refilingSync::class,
\App\Console\Commands\TestCommand::class,
\App\Console\Commands\rollOverCron::class,
\App\Console\Commands\FrontPageRedis::class,
\App\Console\Commands\filingStatusRejectionQueue::class,
\App\Console\Commands\VesselDashboardRedis::class,
\App\Console\Commands\Bookingcountupdate::class,
// \App\Console\Commands\Voyagetwovisit::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$countrylist=array('NL','AR','CL','EC','DE','PH','ID','TT','JM','KR','BE','VN','US','BR','CM','MG','ZA','MU','RU','DO','GT','HN','SV', 'PR','SN', 'TN', 'SI','CI','CR','GM','GN','GY','HR','LC','LR','MR','UY','KH','BD','TH','JP','MM','AT','IE','CH','LB','PY','KE','YT','TZ','MZ','NA','GQ','ME');
foreach ($countrylist as $country) {
$schedule->command('rollOverCron:send ' . $country)
->everyTenMinutes()
->withoutOverlapping();
}
foreach ($countrylist as $country) {
$schedule->command('mainRollover:send ' . $country)
->daily()
->withoutOverlapping();
}
$schedule->command('filingStatusRejectionQueue')
->hourly()
->withoutOverlapping();
$schedule->command('Bookingcountupdate')
->everyTenMinutes()
->withoutOverlapping();
$schedule->command('preAlert')
->hourly()
->withoutOverlapping();
}
protected function commands()
{
require base_path('routes/console.php');
}
}
/**
* Register the Closure based commands for the application.
*
* #return void
*/

Laravel scheduling, knowing how it works helps, so you can debug it when it doesn't work as expected. This does involve diving in the source.
You invoke command on the scheduler, this returns an event.
Let's check how Laravel decides what defines overlapping, we see it expires after 1440 minutes, aka 24 hours.
So after one day, if the scheduled items have not run these scheduled items just stop being scheduled.
We see that a mutex is being used here. Let's see where it comes from. It seems it's provided in the constructor.
So lets see which mutex is being provided. In the exec and the call functions the mutex defined in the Scheduler constructor is used.
The mutex used there is an interface, probably used as a Facade, and the real implementation is most likely in CacheSchedulingMutex, which creates a mutex id using the mutexName from the event and the current time in hours and minutes.
Looking at the mutexName we see that the id exists out of the expression and command combined.
To summarise, all events called in one Scheduler function, share the same mutex that is used in checking if method calls don't overlap, but the mutex generates an unique identifier for each command, including differing parameters, and based on the time.
Your scheduled jobs will expire after 24 hours, which means that with jobs that take 2 hours to complete, you'll get about 12 jobs in a day completed. More if the jobs are small, less if the jobs take longer. This is because PHP is a single threaded process by default.
First task 1, then task 2, then task 3. Etc... This means that if each tasks takes 2 hours, then after 12 tasks their queued jobs expire because the job has been running for 1440 minutes and then the new jobs are scheduled and it starts again from the top.
Luckily there is a way to make sure they run simultaneously.
I suggest you add ->runInBackground() to your scheduling calls.
$schedule->command('rollOverCron:send ' . $country)
->everyTenMinutes()
->withoutOverlapping()
->runInBackground()
->emailOutputTo(['ext.amourya#cma-cgm.com','EXT.KKURANKAR#cma-cgm.com']);cgm.com']);
}

Related

Laravel Queue - Pause between jobs

I want to create a queue (AMAZON SQS) that only runs jobs every X sec. So if suddenly 50 jobs are submitted, the end up in the queue. The queue listener then pulls a job, does something and waits X sec. After that, the next job is pulled. Another X sec pause. Etc etc
For the queue listener, the sleep option option only determines how long the worker will "sleep" if there are no new jobs available. So it will only sleep if there is nothing in the queue.
Or should I just put in a pause(x) in my PHP code?
[edit] I just tested the sleep method with a FIFO and standard AWS SQS queue and this messes up the whole queue. Suddenly jobs are (sucesssfully) resubmitted 3 times after which the go into failed state. Moreover, the delay that is given in my code (3-4 min) was ignored, instead a one minute was taken
<?php
namespace App\Jobs;
use App\City;
class RetrieveStations extends Job
{
protected $cities;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct ($cities)
{
$this->cities = $cities;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
// code here
doSomething()
sleep(X);
}
}
I have the exact same problem to solve. I'm using Laravel 5.8 and I don't see how I can get the queue worker to wait a fixed period between jobs.
I'm now thinking of using a scheduled task to handle this. I can schedule a task to run, say, every 5 minutes and run the following artisan command:
$schedule->command('queue:work --queue=emails --once')->everyFiveMinutes();
This will take one job from the queue and run it. Unfortunately, there's not much more granular control over how often a job is processed.
Exactly, you need to set asleep your php code, there is no other way.
Php sleep

Laravel second task schedule never runs

i have cron entry at shared hosting:
* * * * * php web/artisan schedule:run
The problem is that queue:work command works no matter the order, but second task (Closure) that updates video views never runs.
Code from Kernel.php:
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
//Each Video total_video_views will be accurately updated on daily basis.
$schedule->call(function () {
$videos = Video::get();
app('queue')->pushOn('high', new UpdateVideoViews($videos));
})->hourlyAt('30')
->name('updates all video views')
->withoutOverlapping();
//this is alternative to supervisor since shared hosting someties doesnt provide supervisor
//so we use cron instead to keep queue worker up
$schedule->command('queue:work --queue=high,default')
->everyMinute()
->name('keeps queue worker active')
->withoutOverlapping();
}
Is there any way to run it? My suspiction is that queue:work command along "withoutOverlapping()" is kinda maybe blocking any other tasks to process.

Run cron jobs with same cron-time on a 10s interval queue

So basically I couldnt find my answer elsewhere. I'm having an issue with Laravel 5.x in where I have models called 'Bumpers' which can have a certain cron-time value (say 'every 25 minutes').
Many bumpers can have the same cron-time, meaning that at a certain time, many of these bumpers may be executed using the Laravel Scheduler. However, I need to run these bumpers 10 seconds apart from eachother. So if 10 bumpers are triggered at 8:00:00PM, I need the queue to run with 10 seconds interval until all bumpers have been executed.
I've tried adding sleep(); to the $schedule->call(function(){executeStuff(); sleep(10)});. That worked for a bit but unfortunately it only works for queues not exceeding 60 seconds because then the Scheduler is ran again:
// This function is called on "artisan schedule:run"
protected function schedule(Schedule $schedule)
{
// Get only the active bumpers.
$bumpers = Bumper::where('status', 1)->get();
// Register all bumpers through their occurrence value.
foreach ($bumpers as $bumper) {
// Check for member/admin. All other bumpers are neglected.
if ($bumper->user->canBump()) {
$schedule->call(function () use ($bumper) {
sleep(10);
$bumper->post();
})->cron($bumper->occurrence);
}
}
}
Any solutions?

Laravel possible garbage collector issue: Sessions expire randomly

I have a web app which uses Laravel 4.2 with the session file driver. It runs over a https protocol and all users are stored in one database. We get a lot of reports that users are being randomly logged out, but I can't reproduce the issue in our dev environment. I suspect the garbage collector, could it be cleaning out the wrong session files or something? Should we switch to database session storage?
Here's some of our session config:
'lifetime' => 720,
'expire_on_close' => false,
'lottery' => array(2, 100),
Our php.ini has the gc_maxlifetime set to 43200.
As far as I know the server runs debian 7 with no load balancer or extra session managers installed or configured. Whatever comes with debian 7 is what is used.
Thankful for any help!
No your problem is elsewhere, the lottery is not for selecting sessions to randomly delete, it is to pick random requests to delete EXPIRED sessions and expired sessions only.
In an ideal world you would want in certain acceptable intervals the system to delete all expired sessions but the Laravel developers have decided many will not actually set up the php artisan schedule:run to their CRON Jobs or Scheduled Tasks on the operating system.
So instead of taking every user page requests to run a SQL query to
DELETE FROM sessions WHERE lastactivity < [session_time]
The default 2 in a 100 lottery makes sure this happens during random HTTP requests at the expense of some unluck visitor for price of an average of a tenth miliecond.
You can see in the StartSession middleware where it cleans up the sessions using the method collectGarbage which cleanrs the session based on the lottery config (above).
https://github.com/illuminate/session/blob/master/Middleware/StartSession.php
The default configurations are [2, 100]. It means that a random integer is chosen between 1 and 100, if it's lower or equals to 2 the cache will be cleared. (Aka you the visitor have a 2% possibility to clear the cache every call).
You can enhance this if you think this is what is happening to it becoming a php artisan command that you place in the Kernel.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Session; //for sake of simplicity I am assuming this exists
class PruneExpiredSessions extends Command
{
protected $signature = 'sessions:prune';
protected $description = 'Override default DB Session garbage collection';
public function handle()
{
Session::where('last_activity',< time()-(60*60*48))->delete();
$this->info('Successfully deleted Expired Sessions' );
return Command::SUCCESS;
}
}
Now simply in app/console/kernel.php
<?php
namespace App\Console;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
$schedule->command('telescope:prune --hours=48')->daily();
$schedule->command('session:prune')->daily(); <--This is the line
}
...
}
Just make sure to add php artisan schedule:run to your OS Scheduled Taks/Cron Job every minute

HHVM - Running resource extensive php daemons

Hi i'm trying to use hhvm to run all of the background PHP workers that are currently there in my application. I don't want to run hhvm as a server as Apache is already taking care of it , all i want to do is to run my php codes with hhvm, instead of the regular Zend engine.
Ok here are the codes which i want to run.
This is the entry point of the computationally intensive modules that i want to run
-------------**RunRenderer.php**--------------
#!/usr/bin/php
<?php
require_once 'Config.php';
require_once 'Renderer.php';
Renderer::getInstance()->run();
?>
Here is just a small a portion of the main controller that controls/forks/manages thousands of php tasks/processes.
----------------------------Renderer.php---------------------
<?php
require 'Workers/BumpMapsCalc.php';
/**
* Main Entry class of the Map rendering module
*
* Create workers for all of the different maps calc sub routines
*
*
*
*/
class Renderer extends \Core_Daemon {
/**
* the interval at which the execute method will run
*
* Interval : 10 min
*
*/
protected $loop_interval = 600;
/**
* Set the chunk size
*/
protected $chunkSize = 500;
/**
* Loop counter
*/
protected $loopCounter;
/**
* Low limit and the high limit
*/
protected $lowLimit;
protected $highLimit;
/**
* set the plugins for lock file and settings ini files
*
*/
protected function setup_plugins() {
$this->plugin('Lock_File');
$this->plugin('settings', new \Core_Plugin_Ini());
$this->settings->filename = BASE_PATH . "/Config/settings.ini";
$this->settings->required_sections = array('geometry');
}
protected function setup() {
$this->log("Computing Bumps Maps");
}
/**
* Create multiple separate task that will run in parallel
* Provide the low limit and the high limit which should effectively partition
* the whole table into more manageable chunks , thus making importing and
* storing data much faster and finished within 10 min
*
*/
protected function execute() {
for ($this->loopCounter = 1 ; $this->loopCounter <= $this->settings['geometry']['number'] ; $this->loopCounter += $this->chunkSize) {
$this->lowLimit = $this->loopCounter;
$this->highLimit = $this->loopCounter + $this->chunkSize;
$this->task(new LocalBumpMaps($this->lowLimit, $this->highLimit));
}
}
protected function log_file() {
$dir = BASE_PATH . "/Logs";
if (#file_exists($dir) == false)
#mkdir($dir, 0777, true);
return $dir . '/log_' . date('Y-m-d');
}
}
?>
So normally i would run the program as
php RunRenderer.php -d -p ./pid/pid $1
which would invoke the default zend engine and Renderer.php would fork around thousands of instances of LocalBumpMaps ( along with 100 other map rendering classes ). Now with each of this subtasks taking around 20-30 mb all of the memory in the workstation gets exhausted pretty quickly thus causing the system to screech to a halt.
Of course the main rendering engine is written in C++, but due to some weird requirement the whole front end is in PHP. And the php modules needs to perform around billions of calculations per second. So the only options that was left was to use HHVM in hopes of some significant increase in performance and efficiency.
But the problem is i can't get this code to run with hhvm. This is what i'm trying
hhvm RunRenderer.php -p ./pid $1
This doesn't do anything at all. No processes are forked, no output, nothing happens. So can anyone please tell me how do i run the php scripts with hhvm instead of zend.
I hope my question makes sense, and i would really appreciate any help.
Thanks,
Maxx
Just run the following line first without forking a process:
hhvm RunRenderer.php
If you see console output, and that you can Ctrl+C to terminate the process, then you can demonize the process with an Upstart script. Create a file called /etc/init/renderer.conf:
start on startup
stop on shutdown
respawn
script
hhvm RunRenderer.php
end script
Then you can manually start and stop the process by running:
start renderer
and
stop renderer
If you are running Ubuntu 12.04LTS and above, a log file will be created for you automatically under the name /var/log/upstart/renderer.log. You can fetch live output by tailing the file:
tail -f /var/log/upstart/renderer.log

Categories