2015-04-13 2 views
7

Я хочу асинхронно вызывать команду из контроллера в Symfony2.Асинхронное вызов команды в Symfony2

До сих пор я нашел следующее решение:

$cmd = $this->get('kernel')->getRootDir().'/console '.(new MLCJobWorkerCommand)->getName().' '.$job->getId().' 2>&1 > /dev/null'; 
$process = new Process($cmd); 
$process->start(); 

Есть ли лучший способ сделать это?

Edit:

мне нужен процесс, чтобы работать в фоновом режиме и контроллер, чтобы вернуться сразу после начала первого. Я пробовал:

$cmd = $this->get('kernel')->getRootDir().'/console ' 
    .(new MLCJobWorkerCommand)->getName() 
    .' '.$job->getId().' 2>&1 > /dev/null & echo \$!'; 
$process = new Process($cmd); 
$process->mustRun(); 
$params["processid"] = $process->getOutput(); 

, но контроллер не возвращает ответ до тех пор, пока процесс не завершится.

+2

Проблема заключается в том, что новый процесс остановится, как только родительский процесс останавливается, а также, что является ограничением в PHP. Лучшим решением может быть использование системы массового обслуживания, такой как RabbitMQ. – Gerry

+0

Это великолепно выглядит, я попробую. Раньше я начинал фоновый процесс на PHP в соответствии с моим редактированием, но контроллер блокирует здесь. Это связано с вашим комментарием? – dmb

ответ

4

Я согласен с Gerry, что если вы хотите быть «асинхронно», то вы выбрали не лучший способ

я могу рекомендовать альтернативный вариант RabbitMQ: JMSJobBundle
http://jmsyst.com/bundles/JMSJobQueueBundle/master/installation

Где вы можете создать очереди вам консольные команды что-то вроде:

class HomeController ... { 
    // inject service here 
    private $cronJobHelper; 
    // inject EM here 
    private $em; 

    public function indexAction() { 
     $job = $this->cronJobHelper->createConsoleJob('myapp:my-command-name', $event->getId(), 10); 
     $this->em->persist($job); 
     $this->em->persist($job); 
     $this->em->flush(); 
    } 
} 


use JMS\JobQueueBundle\Entity\Job; 

class CronJobHelper{ 

    public function createConsoleJob($consoleFunction, $params, $delayToRunInSeconds, $priority = Job::PRIORITY_DEFAULT, $queue = Job::DEFAULT_QUEUE){ 
     if(!is_array($params)){ 
      $params = [$params]; 
     } 

     $job = new Job($consoleFunction, $params, 1, $queue, $priority); 
     $date = $job->getExecuteAfter(); 
     $date = new \DateTime('now'); 
     $date->setTimezone(new \DateTimeZone('UTC')); //just in case 
     $date->add(new \DateInterval('PT'.$delayToRunInSeconds.'S')); 
     $job->setExecuteAfter($date); 

     return $job; 
    } 
} 
+0

Спасибо, JMSJobBundle, похоже, именно то, что мне нужно. – dmb

0

Checkout AsyncServiceCallBundle, он позволяет вызывать методы своей службы полностью асинхронно USI ng this подход. Процесс, ответственный за обработку текущего запроса, не ждет завершения его дочернего процесса.

Все, что вам нужно это назвать так:

$pid = $this->get('krlove.async')->call('service_id', 'method', [$argument1, $argument2]); 
Смежные вопросы