Handle() function in console command not being invoked - php

I am having problems with Laravel's console commands. My issue is that the handle() function is not being invoked automatically when running my scheduled jobs in the Console kernel using systemd (rather than crontab).
Let me try and clarify further what is going on:
The handle() function IS invoked automatically when calling 'php artisan my:command' from the console
The handle() function IS invoked automatically when my scheduled jobs are executed by calling artisan in the ctontab
The handle() function IS NOT being invoked automatically when my scheduled jobs are executed by calling artisan as a SYSTEMD task.
The key difference here is that handle() is called when using crontab, but not when using systemd.
Does anybody with knowledge of systemd scheduling have an idea as to why this is? I can see from the system journal that my commands are being called by the systemd service, however, the handle() function is never invoked.
You might say, why not use crontab? However this is not an approach I can take and don't see a reason why it shouldn't work anyway. Help would be appreciated!
This is my systemd artisan.service:
[Unit]
Description=Artisan service
After=network.target
[Service]
Type=simple
Environment=TLNN=/opt/tlnn
ExecStart=/usr/bin/php /srv/www/tlnn/artisan schedule:run
[Install]
WantedBy=multi-user.target
Kernel.php:
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\Classes\InfoCommunications;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
\App\Console\Commands\SendData::class,
\App\Console\Commands\RefreshData::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule( Schedule $schedule )
{
$schedule->command( 'TLNN:SendData' )->cron( '*/1 * * * *' );
$schedule->call( 'TLNN:RefreshData' )->twiceDaily( 6, 18 );
}
}
Example Console command:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Classes\TlnnInfoCommunications;
class SendData extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'TLNN:SendData';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Description here...';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$tlnnInfoCommunications = new TlnnInfoCommunications();
$tlnnInfoCommunications->Run();
}
}

I now have the solution.
The systemd service 'Type' should be set to 'forking' and not 'simple'.
Therefore, changing the artisan.service to the following resolves the issue:
[Unit]
Description=Artisan service
After=network.target
[Service]
Type=forking
Environment=TLNN=/opt/tlnn
ExecStart=/usr/bin/php /srv/www/tlnn/artisan schedule:run
[Install]
WantedBy=multi-user.target
Not to forget a 'systemctl daemon-reload' after changing the serivce.

Related

Laravel Command Schedule Not Working Properly

I'm building a project with Laravel 7.28 on localhost. I need to update a PDF every hour. For the beginning I created a command:
<?php
namespace App\Console\Commands;
use App\Event;
use Illuminate\Console\Command;
class PDF extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'pdf:update';
/**
* The console command description.
*
* #var string
*/
protected $description = 'All Country PDFs updated';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
$event = new Event();
$event->user_id = 1;
$event->save();
echo 'done';
}
}
It just insert a record into events table and works fine. Then I edited the Kernel.php under App\Console directory.
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
Commands\PDF::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('pdf:update')->everyMinute();
}
/**
* Register the commands for the application.
*
* #return void
*/
protected function commands()
{
$this->load(__DIR__ . '/Commands');
require base_path('routes/console.php');
}
}
Finally, I run php artisan schedule:run. I was expecting that the command runs every minute but it just runs once. is this a problem on localhost or did I do something wrong?
The php artisan schedule:run just runs once by its definition:
The schedule:run Artisan command will evaluate all of your scheduled
tasks and determine if they need to run based on the server's current
time.
If you want to do it every minute you should use a scheduled process control system like supervisor or crontab or etc. (more info here)
In case if you are using laravel 8.x and running on a development/local server you can use the following command and it will work for you:
php artisan schedule:work
For Laravel 7 you can also use below command to run in your local
while true; do php artisan schedule:run; sleep 60; done
On windows localhost
First of all set your desired schedule job on the run method inside
App\Console\Kernel More information on the Laravel website page here
Secondly on the command line run the following
command
php artisan schedule:work

Laravel Deployments Idea

I am developing a Laravel application for a client company of mine. That company has a server guy. In the middle of the development process, I asked him to set up a server for the application. But he set up a server without any kind of automated deployments procedure instead he gave me a C-Pannel to deploy the changes manually. The application became so complex and now manual deployments became a very tedious task. I am manually building js and css and uploading them to the server. After a heated argument with him, I finally made him work on automated deployments. Instead of properly putting deployments he has put it this way.
<?php
//app/Console/Commands/GitPull.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class GitPull extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'git:pull';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Get updates from git server';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
exec('git pull origin master');
}
}
<?php
app/Console/Kernel.php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
Commands\GitPull::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('git:pull')
->everyMinute();
}
/**
* Register the commands for the application.
*
* #return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
Basically he has put a scheduler to execute git pull every minute. Is this the correct way to put deployments? What are the drawbacks in this way? Do the deployments have to be dependent on the application? Is it possible to add automated deployments without the help of the laravel framework? I am not very familiar with dev-ops.
Also, my source code is in bitbucket. I am ready to answer any questions regarding this. Thanks in advance.
I certainly would not use a Laravel command to run deployments. Automated deployments can be as simple or complex as needed, but here are some things I expect a build agent to do:
Listen to changes to master to do a production deploy
Run tests (and alert and stop deployment if they fail)
Build my static assets (js/css/etc)
Copy code to server (several ways to do this)
Run migrations
Restart queues so they are running with latest code
Since you're on bitbucket you could look into pipelines to do your ci/cd.

how to change laravel jobs time

I'm developing the app for the customer and he wants to start some jobs in special time
I must run it in jobs, that's right?
for example, he wants to publish a post have 2 status published or waiting
and in send page, he can set time for publish post
how I can develop this in jobs?
ScanJob::dispatch($property->Name, $property->Owner, $Scan->id)->delay(Carbon::now()->addHour(Carbon::now()->diffInHours($Time)));
it's my first try
get diff time in hours and add it from delay
There are basically two ways via which you can solve your problem:
Create a Laravel Artisan command(you can use other methods also that Laravel provides, but I found Artisan to be fun and more flexible, helps avoid the rework) and schedule it accordingly.
Create a Queued Job and dispatch it for some later time, but it has some limitation like, the Amazon SQS queue service has a maximum delay time of 15 minutes.
Now, what is to be done:
In my opinion, you should use Solution 1 as it is more flexible and gives you more control.
Queues are used for 2 things. First, ideally, the task you want to perform should be done in the next 30-45 minutes. Second, the task is time intensive and you don't want to block the thread because of that.
Now the FUN part.
Note: You need not worry, Laravel will perform the majority of the steps for you. I am mentioning each and every step for the sake of not skipping the knowledge.
Step 1: Run the following command to create an Artisan Console Command(Remember to be in your project's root path.):
php artisan make:command PublishSomething
The command will now be available for further development at app/Console/Commands.
Step 2: You will see a handle method inside the Class like following, this is where all of your logic will exist.
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class PublishSomething extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'something:publish';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Publishes something amazing!';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
//
}
}
Step 3: Let's add some logic inside our handle method
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$this->info('Publishing something cool!');
// you can add your own custom logic here.
}
Step 4: After you have added your logic, now we need to test it, you can do so like:
php artisan something:publish
Step 5: Our function is running all fine. Now we will schedule the command. Inside app/Console you will find a file Console.php, this class is responsible for all task scheduling registration, in our case.
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
}
/**
* Register the commands for the application.
*
* #return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
Notice the schedule function here, this is where we will add the schedule logic.
Step 6: Now we will schedule our command to run every 5 minutes. You can change the time period very easily, Laravel provides some pre-made frequency options, and you have your own custom schedule also.
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('something:publish')->everyFiveMinutes(); // our schedule
}
Step 7: Now, Laravel's task scheduler itself is dependent on Cron. So to start the schedule, we will add the following file to our crontab.
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
That's it! We are done. You have created your own custom command and scheduled it for every 5 minutes.
You can learn more about Laravel Artisan Command & Laravel Task Scheduling.
Hope it helps!

How to run Cron Job on Shared Hosting? (Lumen)

I am trying to implement a cron job in my lumen project. I have BookingMaster Table when a user is creating a booking I am setting the default status to B means booked in the table. in the day of booking I am trying to update the status to I to database means In-progress. When I am doing this locally the cron is running perfectly and the status is also updating.
But when I moved this code to my shared hosting it is not working any more. The cron is not updating the status in database.
Location Of the BookingUpdate.php is - app/Console/Commands/BookingUpdate.php
BookingUpdate.php
<?php
namespace App\Console\Commands;
use Helpers;
use Illuminate\Console\Command;
use App\BookingMaster;
class BookingUpdate extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'BookingUpdate:booking-update';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Cron for Booking Update';
public static $process_busy = false;
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle(){
if (self::$process_busy == false) {
self::$process_busy = true;
$where['status'] = 'B';
$update = BookingMaster::updateRecord(6,$where);
self::$process_busy = false;
echo 'Done';
return true;
} else {
if ($debug_mode) {
error_log("Process busy!", 0);
}
return false;
}
}
}
karnel.php
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
'\App\Console\Commands\BookingUpdate',
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
//
}
}
Cron Job Command :
/usr/local/bin/php -q /home/rahulsco/public_html/api.pawsticks/artisan schedule:run 1>> /dev/null 2>&1
There might be a several issues with your code not running in Cron.
Maybe the correct path to PHP is not on the /usr/local/bin/php try running Cron with just php -q
Some systems require the script to start with #!/usr/bin/env php or some similar combination.
There is a space in your cron command on this part artisan schedule:run so it might work once you put your command in quotation marks and escape spaces
php -q "/home/rahulsco/public_html/api.pawsticks/artisan\ schedule:run" 1>> /dev/null 2>&1
Finally, if anything else fails I would try logging something to a file and checking after cron runs, maybe there is some other error in your directory configuration causing your script to fail before writing to database and the cron is running fine...
In app/Console/kernel.php, the schedule function should be like this:
protected function schedule(Schedule $schedule) {
$schedule->command('BookingUpdate:booking-update')->daily();
}
Then your BookingUpdate process will run daily at midnight. There are various other options to schedule your task as mentioned here: https://laravel.com/docs/7.x/scheduling#schedule-frequency-options
Also, you can simply execute the cron manually at any time using: php artisan BookingUpdate:booking-update
PS. Replace BookingUpdate:booking-update with $signature variable value defined in your command class you need to execute.
Tested with shared server - linux with laravel/lumen API.
It's working seamlessly.
lynx -dump "here your url for api or any external url you want call"
Note: Wrap your URL inside double quote

caching database queries at midnight?

I'm using Redis in combination with laravel to cache some heavy queries in my application like this:
return Cache::remember('projects.wip', $this->cacheDuration(), function () {
...
});
private function cacheDuration()
{
return Carbon::now()->endOfDay()->diffInSeconds(Carbon::now());
}
At this moment, the cache expires as midnight, but the first person that passes this method in the morning will be the unlucky one that has to execute the query, so i would like to cache all these queries at midnight again. Is there an easy solution to this? Or will i have to manually mimic http calls to the server at night?
A good approach to achieve what you're looking for is to use a scheduler that executes at midnight to warm the cache.
https://laravel.com/docs/5.4/scheduling
First, use php artisan to create the command:
php artisan make:command WarmCache
You should edit it so it looks something like this:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class WarmCache extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'warmcache';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Warms Cache';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
// >>>> INSERT YOUR CACHE CODE HERE <<<<
}
}
You should add the code that warms your cache in the handle() function, depending on what you're trying to cache you may not need to make a http request. However, you can always use something like curl or guzzle to query the page as a http request if you need to.
Then add this to app/Console/Kernel -> $commands:
protected $commands = [
// ...
\App\Console\Commands\WarmCache::class,
// ...
];
Also, add this to app/Console\Kernel schedule() function so that it executes at mignight:
$schedule->command('warmcache')->daily();
Finally, make sure you have set up the crontask that will execute the laravel scheduler:
* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1

Categories