CakePHP: Running a Shell Job from a Controller

Can I use the dispatch manager from the controller?

My task is to start a shell job when a user logs in.

I am using CakePHP 2.0

+6
source share
6 answers

If you cannot mitigate the need to do so, as the dogma suggests, read on.

So, you have a (potentially) long task that you want to complete, and you don't want the user to wait.

Because the PHP code that your user executes occurs during a request that Apache ran, any executable code stops the request until it is completed (unless you click on the Apache request timeout).

If the above is not acceptable for your application, you will need to invoke PHP using an Apache request (i.e. from the command line).

Ease of use, at this stage it would be advisable to notify your user that you are processing data in the background. Something from a message telling them that they can check later on a progress bar that polls your application via ajax to detect job completion.

The easiest approach is to have a cronjob that runs a PHP script (i.e. CakePHP shell) at a certain interval (at least once a minute). Here you can perform such tasks in the background.

However, some problems arise due to background jobs. How do you know when they failed? How do you know when you need to try again? What if it does not complete within the cron interval .. will a race condition occur?

The correct, but more complex setup will be to use a job / message queue system. They allow you to handle the above problems more gracefully, but usually require that you run a background daemon on the server to catch and process any incoming tasks.

How it works, in your code (when the user logs in) you insert the task into the queue. The daemon daemon instantly receives a job (it does not work on the interval, so it always waits) and passes it to the workflow (for example, the CakePHP shell). This is instantaneous, and if you say this - he knows if he works, he knows if he didn’t work, he can try again if you want, and it is not by chance that he processes the same work twice.

There are a number of them, such as Beanstalkd , dropr , Gearman , RabbitMQ , etc. There are also a number of CakePHP plugins (of different ages) that can help:

I had experience using CakePHP with the Beanstalkd library (+ php Pheanstalk ) and the CakePHP queue plugin (first above). I have to lend to Beanstalkd (written in C) for being very lightweight, simple, and fast. However, with regard to CakePHP development, I found that the plugin starts and starts faster because:

  • The plugin comes with all the PHP code you need to get started. With Beanstalkd, you need to write more code (for example, a PHP daemon that polls a queue looking for jobs).
  • The Beanstalkd server infrastructure is becoming more complex. I had to install multiple beanstalkd instances for dev / test / prod and install supervisord to keep track of the processes.)
  • Development / testing is a bit easier as it is a standalone CakePHP + MySQL solution. You just need to enter cake queue add user signup and cake queue runworker .
+13
source

I managed to start the console from the controller / action, see the example below.

 App::uses('ShellDispatcher', 'Console'); ... public function aco_sync() { $command = '-app '.APP.' AclExtras.AclExtras aco_sync -r adminControllers -p UserAdmin'; $args = explode(' ', $command); $dispatcher = new ShellDispatcher($args, false); if($dispatcher->dispatch()) { $this->Session->flash('OK'); } else { $this->Session->flash('Error'); } return $this->redirect(array('action' => 'index')); } 
+8
source

anything is possible, but why do you need it. If you find that you need to do something in the shell, and the actual application will consider using libs.

you paste the code into lib and then call lib from your application and shell.

+2
source

If you need it to initialize AclExtras, the best way:

 App::import('Console/Command', 'AppShell'); App::import('Plugin/AclExtras/Console/Command', 'AclExtrasShell'); $job = new AclExtrasShell(); $job->startup(); $job->dispatchMethod('aco_sync'); 

But avoid this if you are not able to run the console script.

+1
source

In CakePHP-3, you can send shells from the controller and do this in much the same way as in CakePHP-2. This is not mentioned in the documentation.

 // in your controller: $shell = new \Cake\Console\Shell; $shell->dispatchShell('shell_class param1 param2'); // or how the docs suggest $shell->dispatchShell('shell_class', 'param1', 'param2'); 

Beware of stdout and stderr in unit tests .

Sending a shell involves maintaining stdout and stderr using ConsoleLogger and will give you the whole entry in the console if you have something like the code snippet above in the code that you are testing with phpunit.

+1
source
 function getEbayOrder(){ $this->autoRender = false; App::import('Console/Command', 'AppShell'); App::import('Console/Command', 'EbayShell'); $job = new EbayShell(); $job->dispatchMethod('get_orders'); echo "REPONSE"; } 
0
source

Source: https://habr.com/ru/post/892743/


All Articles