CakePHP: запуск задания оболочки из контроллера - PullRequest
8 голосов
/ 14 июля 2011

Можно ли использовать dispatchShell из контроллера?

Моя задача - запустить задание оболочки, когда пользователь зарегистрировался.

Я использую CakePHP 2.0

Ответы [ 6 ]

13 голосов
/ 14 июля 2011

Если вы не можете смягчить необходимость сделать это, как подсказывает догматик, тогда читайте дальше.

Итак, у вас есть (потенциально) долгосрочное задание, которое вы хотите выполнить, и вы не хотите, чтобы пользователь ждал.

Поскольку код PHP, выполняемый вашим пользователем, происходит во время запроса, который был запущен Apache, любой выполняемый код будет останавливать этот запрос до его завершения (если вы не достигнете тайм-аута запроса Apache).

Если вышеперечисленное неприемлемо для вашего приложения, вам нужно будет запустить PHP с помощью запроса Apache (т. Е. Из командной строки).

В отношении удобства использования на данном этапе имеет смысл уведомить пользователя о том, что вы обрабатываете данные в фоновом режиме. Все, от сообщения, сообщающего им, что они могут позже вернуться к вращающейся строке прогресса, которая опрашивает ваше приложение через ajax, чтобы обнаружить завершение работы.

Самый простой подход - иметь cronjob, который выполняет PHP-скрипт (т.е. оболочку CakePHP) через некоторый интервал (как минимум, это один раз в минуту). Здесь вы можете выполнять такие задачи в фоновом режиме.

Однако некоторые проблемы возникают с фоновыми заданиями. Как вы знаете, когда они потерпели неудачу? Как узнать, когда нужно повторить попытку? Что, если он не завершится в интервале cron ... произойдет ли состояние гонки?

Надлежащей, но более сложной настройкой было бы использование системы работы / очереди сообщений. Они позволяют обрабатывать вышеуказанные проблемы более изящно, но, как правило, требуют запуска фонового демона на сервере, чтобы перехватывать и обрабатывать любые входящие задания.

Как это работает, в своем коде (когда пользователь регистрируется) вы вставляете задание в очередь. Демон очереди мгновенно забирает задание (оно не выполняется с интервалом, поэтому всегда ожидает) и передает его рабочему процессу (например, оболочке CakePHP). Это мгновенно, и - если вы скажете это - он знает, сработало ли это, он знает, не сработало ли это, он может повторить попытку, если хотите, и случайно не выполнил одно и то же задание дважды.

Доступно несколько таких типов, как Beanstalkd , dropr , Gearman , RabbitMQ и т. Д. несколько плагинов CakePHP (различного возраста), которые могут помочь:

У меня был опыт использования CakePHP как с Beanstalkd (+ библиотека PHP Pheanstalk ), так и с плагином CakePHP Queue (первый выше). Я должен отдать должное Beanstalkd (написано на C) за то, что он очень легкий, простой и быстрый. Однако, что касается разработки CakePHP, я обнаружил, что плагин быстрее запускается и работает, потому что:

  • Плагин поставляется со всем кодом PHP, необходимым для начала работы. В Beanstalkd вам нужно написать больше кода (например, PHP-демон, который опрашивает очередь в поисках работы)
  • Инфраструктура сервера Beanstalkd становится более сложной. Мне пришлось установить несколько экземпляров beanstalkd для dev / test / prod и установить supervisord, чтобы следить за процессами).
  • Разработка / тестирование немного проще, так как это автономное решение CakePHP + MySQL. Вам просто нужно набрать cake queue add user signup и cake queue runworker.
9 голосов
/ 25 января 2012

Мне удалось запустить консоль из контроллера / действия, см. Пример ниже.

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'));
}
2 голосов
/ 16 мая 2017

В CakePHP-3 вы можете отправлять оболочки с контроллера и делать это почти так же, как в CakePHP-2.В документации это не упоминается.

// 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');

Остерегайтесь stdout & stderr в модульных тестах .

При отправке оболочки включаются ведение журнала stdout и stderr с помощью ConsoleLogger, и вы получите всю запись в вашей консоли, если у вас есть что-то вроде приведенного выше фрагмента кода в коде, который вы тестируете из phpunit.

2 голосов
/ 14 июля 2011

все возможно, но почему вы хотите. Если вы обнаружите, что вам нужно что-то сделать в оболочке, а само приложение посмотрите на использование libs.

вы вставляете код в библиотеку, а затем вызываете библиотеку как из своего приложения, так и из оболочки.

1 голос
/ 02 февраля 2015

Если вы хотите инициализировать AclExtras, лучше всего:

App::import('Console/Command', 'AppShell');
App::import('Plugin/AclExtras/Console/Command', 'AclExtrasShell');

$job = new AclExtrasShell();
$job->startup();
$job->dispatchMethod('aco_sync');

Но избегайте этого, если у вас нет возможности запустить консольный скрипт.

0 голосов
/ 30 января 2015
function getEbayOrder(){
    $this->autoRender = false;

    App::import('Console/Command', 'AppShell');
    App::import('Console/Command', 'EbayShell');

    $job = new EbayShell();
    $job->dispatchMethod('get_orders');

    echo "REPONSE";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...