I need to execute a Laravel long running process in the background for consuming the Twitter Streaming API. Effectively the php artisan CLI command I need to run is
nohup php artisan startStreaming > /dev/null 2>&1 &
If I run that myself in the command line it works perfectly.
The idea is that I can click a button on the website which kicks off the stream by executing the long running artisan command which starts streaming (needs to run in the background because the Twitter Streaming connection is never ending). Going via the command line works fine.
Calling the command programatically however doesn't work. I've tried calling it silently via callSilent() from another command as well as trying to use Symfony\Component\Process\Process to run the artisan command or run a shell script which runs the above command but I can't figure it out.
Update
If I queue the command which opens the stream connection, it results in a Process Timeout for the queue worker
I effectively need a way to run the above command from a PHP class/script but where the PHP script does not wait for the completion/output of that command.
Help much appreciated
The Symfony Process Component by default will execute the supplied command within the current working directory, getcwd().
The value returned by getcwd() will not be the Laravel install directory (the directory that contains artisan), so the command will most likely returning a artisan: command not found message.
It isn't mentioned in the Process Component documentation but if you take a look at the class file, we can see that the construct allows us to provide a directory as the second parameter.
public function __construct(
$commandline,
$cwd = null,
array $env = null,
$input = null,
$timeout = 60, array
$options = array())
You could execute your desired command asynchronously by supplying the second parameter when you initialise the class:
use Symfony\Component\Process\Process;
$process = new Process('php artisan startStreaming > /dev/null 2>&1 &', 'path/to/artisan');
$process->start();
I had a same problem and I solved this with pure php and use proc_open function.
My code :
$descriptionProcOpen = [
["pipe", "r"],
["pipe", "r"],
["pipe", "r"]
];
proc_open("php " . base_path() . "/artisan your:command {$argument}", $descriptionProcOpen, $pipes);
How about queuing the execution of the command via Laravels build-in queues?
$this->callSilently('mail:send', [
'user' => 1, '--queue' => 'default'
]);
https://laravel.com/docs/9.x/artisan#calling-commands-from-other-commands
Related
I have a Laravel App with Short Schedule package installed and a crontab to execute it.
Inside the executed method I have a SHELL_EXEC function with some code inside it.
The problem is that when the code runs automatically using the cron, the SHELL EXEC doesn't work. The output is null.
When I run the method directly using php artisan or by simply running the schedule using php artisan manually, it works.
To have a clear vision of what's going on:
Inside the crontab -e I have the following
* * * * * php /var/www/html/project/artisan short-schedule:run --lifetime=60
The cron executes this method which has the following code:
$shell_command = '/home/paul/elrondsdk/erdpy --verbose tx new --receiver xxxx --send --pem asdfa.pem --gas-limit 300 --nonce 12';
$output = shell_exec($shell_command);
Log::info('output', [$output]);
If it runs automatically using the cron, the $output is NULL.
If I run the command manually, I get a proper output.
Initially I thought I need to specify the exact path in the shell exec because cron doesn't not PATH. Unfortunately did not solve my problem.
Thanks!
I tried to run the command manually or to run php artisan schedule:run and wait and it worked!
It doesn't work ONLY when its runs by the cron.
I am trying to execute a script in a remote server and I am using the symfony process.
$process = new Process('ssh -q root#remoteserver <path 2 script>');
$process->run();
When I execute this, I am getting NULL value.
Please note: The command I used is working fine in bash.
I try to plan one-time job with 'at' command. There is next code in script:
$cmd = 'echo "/usr/bin/php '.$script_dir.$script_name.' '.$args.'"|/usr/bin/at "'.$time.'" 2>&1';
exec($cmd, $output , $exit_code);
When I run this command from script it adds the job to the schelude. This I see by the line in logs job 103 at Thu Sep 3 15:08:00 2015 (same text contains $output). But then nothing happens in specified time like at ignores the job. And there are no error messages in logs.
When I run same command with same args from command line on server it scheludes the job and than runs it at specified time.
I found out that when I try to plan a job via php script it runs under apache user. I tried to run next in command line on server:
sudo -u apache echo "/usr/bin/php /var/www/pant/data/www/pant.com/scripts/Run.php firstarg secondarg "|/usr/bin/at "16:00 03.09.2015"
It works correct too. I checked sudoers and have added apache user with NOPASSWD privileges. Script Run.php has execute rights.
at.deny is empty. at.allow does not exist.
So question is: why 'at' does not run command given via php script (exec) but runs same command in command line? How to run it?
Thanks to all.
I found by chance answer at stackexchange.com:
The "problem" is typically PHP is intended to run as module in a webserver. You may need to install the commandline version of php before you can run php scripts from the commandline
We have a tool which executes the PHP interactive shell like this:
$descriptorSpec = array(
0 => STDIN,
1 => STDOUT,
2 => STDERR
);
$prependFile = __DIR__ . '/../../../../../res/dev/console_auto_prepend.php';
$exec = 'php -a -d auto_prepend_file=' . escapeshellarg($prependFile);
$pipes = array();
proc_open($exec, $descriptorSpec, $pipes);
The trick with auto_prepend_file unfortunately causes issues with autoloading on PHP 5.3. We found out that everyting works well when we include the file inside the interactive shell:
$ php -a
Interactive shell
php > include "myproject/res/dev/console_auto_prepend.php";
Autoloader initialized.
What we want to do is the following:
execute php interactive shell via proc_open
send the include line to the interactive shell
hand over the controll to the user input
Is there any way to do this?
Untested idea:
Created a new input pipe
Open the PHP process (php -a) with that input pipe, stdout and stderr could be connected to the system pipes
Inject the include command (write to the input pipe)
In a loop read from the STDIN and write to our new input pipe (which is connected to the php -a)
The project ended up in using a custom PHP shell (psysh)
I'm using exec to run a background script like this :
$command = "/usr/local/bin/php public_html/r/index.php tools $action process $params > /dev/null &";
exec($command);
The thing is : it's NOT working.
Hints :
When I'm executing the very same command from the terminal (via SSH) it's working fine.
The exec command is enabled (I can execute any command without issue).
Any ideas?
background jobs tend to have different 'current' directories than your shell - usually it's the home directory of the account that the job is running under. Unless your public_html is in /home/whoever, you're not actually running your script. Try an absolute path:
$command = "/usr/local/bin/php /path/to/public_html/r/index.php etc..."
^^^^^^^^^
instead.