Is there any mechanism through which yii2 console command can be scheduled to run at a specific time, with ability to check if the previous job has ended or not.
Related
I have a Product model with id,name,price.
The price value is stored in an external API and i need to fetch it every minute in order to update it in the database.
Looking through the Laravel documentation I found two ways to implement:
Create an artisan command (https://laravel.com/docs/8.x/artisan) and add it to task scheduling (https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands)
Create a job (https://laravel.com/docs/8.x/queues) and add it to task scheduling (https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands)
First of all, is there any other approach i should take in consideration?
If not, which one of the above would be the best approach and why is it correct for my use case?
As per my comments on one of your previous questions on this topic, whether you use a queue or not depends on your use case.
An Artisan command is a process that executes once and performs a task or tasks and then exits when that task is complete. It is generally run from the command line rather than through a user action. You can then use the task scheduling of your command's host operating system (e.g. a CRON job) to execute that command periodically. It will faithfully execute it when you schedule it to be done.
A Queued job will execute when the Job turns up next in the queue, in priority order. Let's say you send your API call (from your other post) to the queue to be processed. Another system then decides it needs to send out emails urgently (with a higher priority). Suddenly, your Job, which was next, is now waiting for 2000 other Jobs to finish (which might take a half hour). Then, you're no longer receiving new data until your Job executes.
With a scheduled job, you have a time critical system in place. With queues, you have a "when I get to it" approach.
Hope this makes the difference clearer.
With laravel it is a lot easy to use the built in scheduler. You have to add only one entry to the crontab and that is to run the command php artisan schedule:run EVERY MINUTE on your project. After that you dont have to thing about configuring the crontab on the server, you just add commands to the laravel scheduler and they will work as expected.
You should probably use Cron Job Task Scheduling which would be the first approach you mentioned.
Commonly for this type of use-cases commands are the easiest and cleanest approach.
There are a few things to do in order to make it work as expected:
Create a new command that will need to take care of hitting the endpoint and storing the retrieved data to the database
In Kernel.php file register your command and the frequency of running (each minute)
Run php artisan schedule:run
You can read more about how to create it here:
I have the Laravel schedule command triggered in the crontab as:
* * * * * php /home/forge/site/artisan schedule:run
This is set via Forge.
Then, in app/Console/Kernel.php I'm triggering my job to run hourly:
$schedule->job(new GetRecentArtists())->hourly();
But it's still running every minute.
My understanding was that the artisan command needs running every minute so that job schedules can then be checked to see if the job needs triggering as per its' specific schedule.
Update
I've tried restarting the queue as suggested in the comment by Sahidul, and have confirmed that none of the built-in schedules (hourly, daily, etc) prevent it from running every minute.
When I remove the schedule from the crontab and run it via php artisan schedule:run, I get 'No scheduled commands are ready to run' but the task runs anyway.
This was a red herring. I had my log message showing the job as running in the __construct method of the job, rather than in the handle method.
The job is constructed when the scheduler runs, then added to the queue to be executed as per the schedule - so the construct method was being called immediately, but the job wasn't actually being handled until the scheduled time.
I have a setting section in my laravel application. In this section I have a setting for defining a sync time. So the user can set their preferred time for sync data from laravel application to a third party CRM(Salesforce).
For now, I am storing a sync time into Database table. Now I want to run a cron JOB at that time for a particular user.
I have already created a cron job script and the cron job script is working fine. I am able to test cron job manually I just need to automate it with user setting(Preferred time).
My Cron JOB URL https://my-domain.org/cronjob?user_id=101
I tried to use laravel scheduling but this not fulfillig my requirement.
Is there any other better solution available at laravel?
There is some information missing but I try to assume a few things to hopefully propose a working solution using the Laravel scheduler.
Assuming you store the time at which the CRON runs in the database as 01:00 for 1 o'clock in the night you could do the following:
protected function schedule(Schedule $schedule)
{
User::query()->whereNotNull('cron_time')->each(function (User $user) use ($schedule) {
$schedule->command('app:import', ['user_id' => $user->id])
->withoutOverlapping() // prevents running the same command (+ parameters) twice at the same time, should only be a problem if the command can run > 24 hours, but still a safe thing to do
->dailyAt($user->cron_time);
});
}
I dreamed up that you stored the information on the User model
That you used a flag in the database called cron_time which contains the 01:00 or is null if the cron is disabled
The cron needs to run daily at that user supplied time
The import command is called app:import and is a console command that accept a user_id argument with the user id to run the import for
This might help you adapt the above to how it's structured in you own app.
If you want to use queued jobs to execute the imports you could also create the app:import CLI command to just dispatch that job instead of actually running the import. Depending on the amount of imports it might be a good idea to prevent long running scheduler commands and have the ability to retry and have a timeout.
Another option could also be to have a daily scheduled command that dispatches jobs to the queue scheduled to run at a specific time (which does not work with the SES driver). For more about that see: https://laravel.com/docs/5.8/queues#delayed-dispatching.
I'm writing a CMS with the Laravel as a backend and Vue.js as a frontend. So far, I had no problems with the application, however, when I tried to create Scheduler to manage tasks from the frontend, I'm not able to run these tasks with provided Laravel cron task:
* * * * * php /var/www/html/artisan schedule:run >> /dev/null 2>&1
Well, actually I can, if I redirect the output of the CRON to the file and not /dev/null, Laravel is telling me that the job is executed successfully, however, nothing is happening.
To test out that created Scheduler class is able to call the jobs at an assigned times, I've written small node.js notification application, which simply sends the system notification.
In case if I'm calling the php artisan schedule:run myself, I have no problem with receiving this notification, and yet again, I have a new entry in the log file telling me that job executed successfully.
But when CRON executes the same artisan command, the only thing I get is entry in the log file but no notification.
I'm running Apache server under the same user which has this cron entry and the node.js script is placed under in the home path of this same user. So from here I've no idea why this might happen.
P.S. This is the interface which basically shows how the crontab is edited and what I'm adding to it to make this thing work (but for some reason it is just spitting messages to log without actually doing anything):
And this is how the task looks like:
Laravel provides an easy way for task scheduling. Laravel’s ‘Command Scheduler’ allows you to easily define the schedule of the commands within Laravel itself. When using the scheduler, only one Cron entry is needed on the server.
I would like to be able to test a server side process in my local dev env using a CRON task that runs every minute. However I do not want this to run every minute of every day, just when I need to test the process.
Is there some Terminal command I can use to add a CRON task and another to do the reverse (remove it).
Ideally I'd then like to execute this command via a tool like Shuttle so that I can start/stop the CRON from the taskbar as and when required.
In the end I abandoned this idea and used an app called CronniX to manually start and stop a local CRON process:
https://code.google.com/p/cronnix/