I am using laravel 4.2.
I've a project requirement to send some analysis report email to all the users every Monday 6 am.
Obviously its a scheduled task, hence I've decided to use cron-job.
For this I've installed liebig/cron package. The package is installed successfully. To test email, I've added following code in app/start/global.php:
Event::listen('cron.collectJobs', function() {
Cron::setEnablePreventOverlapping();
// to test the email, I am setting the day of week to today i.e. Tuesday
Cron::add('send analytical data', '* * * * 2', function() {
$maildata = array('email' => 'somedomain#some.com');
Mail::send('emails.analytics', $maildata, function($message){
$message->to('some_email#gmail.com', 'name of user')->subject('somedomain.com analytic report');
});
return null;
}, true);
Cron::run();
});
Also in app\config\packages\liebig\cron\config.php the key preventOverlapping is set to true.
Now, if I run it like php artisan cron:run, it sends the same email twice with the same time.
I've deployed the same code on my DigitalOcean development server (ubuntu) and set its crontab to execute this command every minute but still it is sending the same email twice.
Also it is not generating lock file in app/storage directory, according to some search results I've come to know that it creates a lock file to prevent overlapping. the directory has full permissions granted.
Can anybody knows how to solve it?
Remove Cron::run().
Here's what's happening:
Your Cron route or cron:run command is invoked.
Cron fires off the cron.collectjobs event to get a list of events.
You call Cron::run() and run all the events.
Cron calls Cron::run() and runs all the events.
In the cron.collectjobs event you should only be making a list of jobs using Cron::add().
The reason you're not seeing a lock file is either that preventOverlapping is set to false (it's true by default), or that the jobs are running so fast you don't see it being created and deleted. The lock file only exists for the time the jobs run, which may only be milliseconds.
Related
I am using Laravel 9 and I am trying to set several tasks in my schedule.
One of them should be called every minutes the other every 5 minutes .
protected function schedule(Schedule $schedule)
{
$schedule->call(/* send myself a mail */)->everyMinute();
$schedule->call(/* send myself a mail */)->everyFiveMinutes();
}
On my host I have a cron task called every minutes :
/opt/alt/php81/usr/bin/php ~/my-path/artisan schedule:run
However every minutes I receive the mail from my everyMinute() task, and the mail from my everyFiveMinutes() task.
I tried with job and command instead of call but it doesn't changes anything, same with ->cron('* * * * *') instead of ->everyMinute()
I had the very same issue.
I discover that when I use the schedule like this:
$schedule->call( MyController::MyFunction() )->everyFiveMinutes();
It run every minute, not every 5 minute as it would suppose to run.
If I run like this, every works as expect:
$schedule->call(function () {MyController::MyFunction();})->everyFiveMinutes();
I want to check my stored data at database for every minute if now time has exceeded 'close_at' time. So then I can change the 'status' column to be closed.
I've been thinking that I can ->get() all data from to the table and use looping to check every data's 'close_at' then change the status but that's not effective nor efficient is it?
Got any idea?
To build on the above answers into something more comprehensive :
Make sure cron is executing Laravel's scheduler every minute :
php8.0 /home/yourdomain.com/artisan schedule:run
Make a new Laravel command to execute the relevant logic :
php artisan create:command CloseJobs
Write the necessary code in that class - in this case, retrieve all the relevant open jobs which need to be closed and close them, which we can do through mass assignment in one easy line (make sure your 'status' is added to the $fillable array on your model) :
protected $signature = 'close:jobs';
....
$jobs = Job::where('status', 'open')->where('close_at', '<', now())->update(['status' => 'closed']);
Tell Laravel to execute that task every minute, in App\Console\Kernel.php :
$schedule->command('close:jobs')->everyMinute();
In Laravel, in my Kernel, I have:
protected $commands = [
Commands\SendRenewEmails::class,
];
/**
* 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('renew:emails')
->daily();
}
The said function renew:emails, works as intended if I run this manually trough Artisan.
And in my crontab I have:
* */8 * * * cd /path-to-my-project && php artisan schedule:run >> /dev/null 2>&1
I have this to run every 8th hour, instead of every minute at * * * * *, since this is live for testing, and just to ensure that the task wasnt run every minute.
So how does Laravel know, when to run the daily job on the kernal, and when does this happen?
From this setup (which seems to be the basic setup for cronjobs in Laravel, but to run every minute instead of every 8th hour), there is no logs (that I can see), and no table in DB to keep track of this.
So if I where to set my cron to * * * * *, how does Laravel know not to run the scheduled job every minute, just because I have put ->daily(); at the end of the job?
And when I have daily();, at what specific time is that? And at specific what time is hourly();?
TL;DR:
How does Laravel know not to run the same jobs again if it is not supposed to, for example with daily(); rule? Where is this information stored? How can I be certain that a job with rule daily(); wont run every minute if my cronjobs std:out's php artisan schedule:run every minute?
Under the hood, the Laravel Scheduler uses https://github.com/dragonmantank/cron-expression to determine if a command or job is scheduled to run at the given minute the schedule:run is called.
Each task you schedule translates to a cron expression, which is then passed into the package. A method called isDue is then run against that expression to determine whether or not it should run. So, if you set a task to run hourly, then isDue will yield true at the top of the hour, and Laravel will execute to the task within the cron cycle.
As such, the information does not need to be stored anywhere, as determination is done on the fly.
This might also lead you to wonder what might happen if you have a long-running task that might take longer than the interval. This is where withoutOverlapping comes into the picture. When called, it creates what is known as a mutex, which is similar to a 'lock' of sorts (see What is a mutex? for more information), when the task is initially run. If a mutex already exists for a particular task on subsquent cycles, it means that task is currently running in another cycle, and should not be triggered again in this one.
Where are mutexes stored? Simple: Laravel stores them in a cache, and when a mutexed task is finished, the mutex is removed from the cache. And so the cycle continues.
I could go into much further detail here, but I think this answers your question for the most part.
I am using a Beanstalkd queue to deploy jobs in my Laravel 5.3 application. I use Laravel Forge to administer the server.
I have one of two scenarios that occur:
1) I set a max number of attempts, which causes every job pushed to the queue to be placed on the failed jobs table - even if its task is completed successfully, resulting in this exception on the jobs table:
Illuminate\Queue\MaxAttemptsExceededException: A queued job has been attempted too many times. The job may have previously timed out
And this in my error log:
Pheanstalk\Exception\ServerException: Server reported NOT_FOUND
2) If I remove the max attempts, the jobs run successfully but in an infinite loop.
I am assuming that I am not removing these jobs from the queue properly and so in scenario #1 the job is failing because just wants to keep running.
My controller pushes my job to the queue like this:
Queue::push('App\Jobs\UpdateOutlookContact#handle', ['userId' => $cs->user_id, 'memberId' => $member->id, 'connection' => $connection]);
Here is the handle function of my job:
public function handle($job, $data)
{
Log::info('Outlook syncMember Job dispatched');
$outlook = new Outlook();
$outlook->syncMember($data['userId'], $data['memberId'], $data['connection']);
$job->delete();
}
Here is a picture of my queue configuration from the Laravel Forge admin panel. I am currently using the default queue. If "Tries" is changed to ANY, the jobs succeed but run in an infinite loop.
How do I properly remove these jobs from the queue?
I have a laravel queue setup to a database. When I run dd(env('QUEUE_DRIVER')) I get database back. When I create a job it is run right away. I would like the job to be queued until I run php artisan queue:work. What do I need to do to have the job not run right away. Thanks!
Edit 1:
Dispatch Code:
for ($i=0; $i < 100; $i++) {
$job = new UpdateJob("");
dispatch($job);
}
Job Code:
public function handle(){
sleep(30);
SlackApi::SendMessage("Job!");
}
When I run this I get a slack message every 30 seconds. But none of these jobs are being stored in the DB.
Edit 2:
Even when I add ->delay(Carbon::now()->addMinutes(10)) to the job the job is still run right away.
The issue seems to come from upgrading from v5.1 to v5.4 I added Illuminate\Bus\BusServiceProvider::class to my providers in app.php and that fixed everything.
Is any supervisor running? if the supervisor is configure the queue will be take care of the job as son as it's added to the queue. if you want a delayed dispatch of the job you must specify the delay. Take a look into https://laravel.com/docs/5.4/queues#delayed-dispatching for more details