Tailing a log within Laravel never executes Symfony Process callback - php

I'm trying to tail a log file using a console command to detect specific errors. However, the call back in the run(...) portion of my script is never called in the Symfony Process:
use Illuminate\Console\Command;
use Symfony\Component\Process\Process;
class MonitorLogs extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'monitor:logs {log}';
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$command = "tail -n 1 -f " . escapeshellarg($this->argument('log'));
(new Process($command))
->setTty(true)
->setTimeout(null)
->run(function ($type, $line) {
$this->info('test');
});
}
}
I tried tracing with Xdebug any my break point at $this->info() is never reached. I can add lines to the log file I am testing with and they show up in my console while the script is running, but that line to output the word test is never hit.
What is wrong here?

Please remove setTty(true) and the output should display accordingly

Related

Execute Server Commands on Laravel 7 Scheduler

I have 2 commands in my Laravel 7 Schelduler
$schedule->command('inspire')->everyMinute()->emailOutputTo(env('MAIL_TO'));
$schedule->exec('whoami')->everyMinute();
✅ The first one works perfectly, I get the email
❌ This second one doesn't work at all
$schedule->exec('whoami')->everyMinute();
I followed: https://laravel.com/docs/7.x/scheduling
Any hints for me ?
My guess is that whoami runs fine but nothing is done with the output.
Can you try to add emailOutputTo(env('MAIL_TO')); to the second command to see if you get an email with the output ?
Please check the documentation about outputting the result from exec: https://laravel.com/docs/7.x/scheduling#task-output
as #Clément Bisaillon suggests, you have forgotten to add method for shell command output.
but your comment has been Raised a new Question.
Why it works with whoiam and date, but not working with history ?
This Works:
$schedule->exec('cat /home/abilogos/.bash_history ')->everyMinute()->appendOutputTo('/home/abilogos/Desktop/testHist.txt');
you can find history file in with echo $HISTFILE
BUT WHY?
it gets even more interesting when you just which history to find history path and it tells you there
which: no history in Your Path
like source command.
because they are not Programs stored in $PATH locations. they are bash`s command
http://manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html
and laravel uses php #proc_open (Symfony\Component\Process\Process) which just execute Programs not Bash commands :
https://www.php.net/manual/en/function.proc-open.php
Temporarily
I created this
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class exec extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'exec {cmd}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Run any command(s)';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$cmd = $this->argument('cmd');
$this->info(shell_exec($cmd));
}
}
and use it like this
$schedule->command('exec date')->everyMinute()->emailOutputTo(env('MAIL_TO'));
$schedule->command('exec history')->everyMinute()->emailOutputTo(env('MAIL_TO'));
It works !!

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

Laravel 4.2 Indatus/dispatcher - Command no defined

I'm using Indatus/dispatcher for Laravel 4.2. It is basically a Cron job based Task Scheduler.
I am trying to run a Cron job every minute, and I am getting this error on the live server (but it works fine on my local machine). Here is what I have done:
<?php
use Indatus\Dispatcher\Scheduling\ScheduledCommand;
use Indatus\Dispatcher\Scheduling\Schedulable;
use Indatus\Dispatcher\Drivers\Cron\Scheduler;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class TestCommand extends ScheduledCommand {
/**
* The console command name.
*
* #var string
*/
protected $name = 'command:check';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Check if the meberships are verified.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* When a command should run
*
* #param Scheduler $scheduler
* #return \Indatus\Dispatcher\Scheduling\Schedulable
*/
public function schedule(Schedulable $scheduler)
{
return $scheduler->everyMinutes(1);
}
/**
* Execute the console command.
*
* #return mixed
*/
public function fire()
{
Log::info('I was here # ' . date('H:i:s'));
}
/**
* Get the console command arguments.
*
* #return array
*/
protected function getArguments()
{
return array(
// array('example', InputArgument::REQUIRED, 'An example argument.'),
);
}
/**
* Get the console command options.
*
* #return array
*/
protected function getOptions()
{
return array(
// array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
}
}
So basically, I'm just writing a line in my log file (i.e. Storage/laravel.log) every time the scheduler is run. When I do php artisan scheduled:run on my local machine, it writes a new line in my log file.
Now, I've uploaded the code on my server and have created a Cron job as:
The Cron job is running every minute as expected and the log file is also being updated every minute, but instead of the message I am writing in log file, its writing following error every minute:
[2016-09-24 09:20:01] production.ERROR: exception 'InvalidArgumentException' with message 'Command "command:check" is not defined.
Did you mean this?
command:make' in /home/mhjamil/public_html/l4-cron/test/vendor/symfony/console/Symfony/Component/Console/Application.php:564
Stack trace:
#0 /home/mhjamil/public_html/l4-cron/test/vendor/symfony/console/Symfony/Component/Console/Application.php(190): Symfony\Component\Console\Application->find('command:check')
#1 /home/mhjamil/public_html/l4-cron/test/vendor/symfony/console/Symfony/Component/Console/Application.php(124): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#2 /home/mhjamil/public_html/l4-cron/test/artisan(58): Symfony\Component\Console\Application->run()
#3 {main} [] []`
And by the way, I've registered the command in app/start/artisan.php as
Artisan::add(new TestCommand);
Also the command php artisan command:check runs successfully on my local machine, but when I upload it to my server it says Command "command:check" is not defined.
And one more thing, on my server I have added a route and did Artican::call("command:check");. Now whenever I reload this page, it logs an entry successfully in the log file. But its giving error when done through cron job. So I am guessing the problem is somewhat related to cron job or server settings.
I have tried changing cron command to:
/usr/bin/php /home/mhjamil/public_html/l4-cron/test/artisan command:check 1>> /dev/null 2>&1
previously I was using schaduled:run but still same issue :(

Scheduling tasks after polling the database php

I am building web app in PHP which is used to schedule tasks in the future. In the background I am supposed to Poll the database every 2 min to see if there is any upcoming task. How do I implement polling. Javascript solution is not helpful as the user can be on any of the pages on the webapp, but the system should keep pooling the DB.
Cron is one way but still I have to poll the database to create a cron job. What is the best way to implement it?
Thanks
Create a cron job that is executed once every X minutes and make that job check the DB. If there is a new upcoming task, just make the job launch it.
Create an 'execute:tasks' artisan command, so you can poll your database whenever you need to execute your tasks. You should be able to run it this way:
php artisan execute:tasks
Your command will call some controller action (or a class method) to poll the database and find if there are tasks available to be executed.
Then you just need to create a cron job that will execute that artisan command every 2 minutes:
*/2 * * * * php artisan execute:tasks
This is an example of Artisan command:
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class ExecuteTasksCommand extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'execute:tasks';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Find and execute available tasks.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return void
*/
public function fire()
{
(new ExecuteTasksClass)->findAndExecute();
}
}
You just have to name this file something like app/commands/ExecuteTasksCommand.php
And add this to app\start\artisan.php:
Artisan::add(new ExecuteTasksCommand);

Categories