dmb dmb - 4 days ago 5
PHP Question

Asynchronously calling a Command in Symfony2

I want to asynchronously call a Command from within a Controller in Symfony2.

So far i found the following solution:

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


Is there a better way to accomplish this?

Edit:

I need the Process to run in background and the Controller to return right after it started the former. I tried:

$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();


but the Controller doesn't return a Response until the Process has finished.

Answer

I agree with Gerry that if you want to be "asynchronously" then you selected not the best way

I can recommend an alternative of RabbitMQ: JMSJobBundle
http://jmsyst.com/bundles/JMSJobQueueBundle/master/installation

Where you can create a queue of you console commands something like:

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;
    }
}
Comments