简体   繁体   中英

Execute shell from controller CakePHP 3.x

I have a specific task in a CakePHP Shell and it's executed by a CRON job. But I want the users to be able to execute it from a web interface (like a button or something like this) whenever he wants.

So, my question is, is this possible to execute a shell from a controller ?

Emulate this in a controller:

bin/cake MyShell

I know it was possible in the previous versions of CakePHP, but I didn't find something related to this in the newest version. And use exec("bin/cake MyShell") seems really dirty to me.

create a shell object , the call any of its function to want to excute

 $myShell = new \App\Shell\MyShell;
 $myShell->anyShellFun();

in order to call shell from your controller function you need to do this in your controller function :

namespace App\Controller;

use App\Controller\AppController;
use Cake\Console\ShellDispatcher; //use this shell dispacher

/**
* Example Controller
*
*/
class ExampleController extends AppController
{

/**
 * Index method
 *
 * @return \Cake\Network\Response|null
 */
public function index()
{
    $shell = new ShellDispatcher(); //create object of your Shell Dispatcher
    $output = $shell->run(['cake', 'foo']); //here foo is your shell name

    if (0 === $output) {
        $this->Flash->success('Success from shell command.');
    } else {
        $this->Flash->error('Failure from shell command.');
    }

    return $this->redirect('/');
  }
}

hope this answer your question, if any problem leave a comment.

thank you.

If you can't mitigate the need to do this as dogmatic suggests then, read on.

So you have a (potentially) long-running job you want to perform and you don't want the user to wait.

As the PHP code your user is executing happens during a request that has been started by Apache, any code that is executed will stall that request until it completion (unless you hit Apache's request timeout).

If the above isn't acceptable for your application then you will need to trigger PHP outwith the Apache request (ie. from the command line).

Usability-wise, at this point it would make sense to notify your user that you are processing data in the background. Anything from a message telling them they can check back later to a spinning progress bar that polls your application over ajax to detect job completion.

The simplest approach is to have a cronjob that executes a PHP script (ie. CakePHP shell) on some interval (at minimum, this is once per minute). Here you can perform such tasks in the background.

Some issues arise with background jobs however. How do you know when they failed? How do you know when you need to retry? What if it doesn't complete within the cron interval.. will a race-condition occur?

The proper, but more complicated setup, would be to use a work/message queue system. They allow you to handle the above issues more gracefully, but generally require you to run a background daemon on a server to catch and handle any incoming jobs.

The way this works is, in your code (when a user registers) you insert a job into the queue. The queue daemon picks up the job instantly (it doesn't run on an interval so it's always waiting) and hands it to a worker process (a CakePHP shell for example). It's instant and - if you tell it - it knows if it worked, it knows if it failed, it can retry if you want and it doesn't accidentally handle the same job twice.

There are a number of these available, such as Beanstalkd , dropr , Gearman , RabbitMQ , etc. There are also a number of CakePHP plugins (of varying age) that can help:

I have had experience using CakePHP with both Beanstalkd (+ the PHP Pheanstalk library) and the CakePHP Queue plugin (first one above). I have to credit Beanstalkd (written in C) for being very lightweight, simple and fast. However, with regards to CakePHP development, I found the plugin faster to get up and running because:

  • The plugin comes with all the PHP code you need to get started. With Beanstalkd, you need to write more code (such as a PHP daemon that polls the queue looking for jobs)
  • The Beanstalkd server infrastructure becomes more complex. I had to install multiple instances of beanstalkd for dev/test/prod, and install supervisord to look after the processes).
  • Developing/testing is a bit easier since it's a self-contained CakePHP + MySQL solution. You simply need to type cake queue add user signup and cake queue runworker .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM