1

I am using Symfony2 and I want to run a long script written in C++ (for example 60 minutes).

Now I do it via shell_exec():

$pid = shell_exec('nohup my/program/written/in/c++.out some arguments > /dev/null 2>/dev/null & echo $!');

If I keep refreshing a page the script runs fine, but if I go AFK the script is terminated with process of PHP server (/usr/bin/php-cgi).

Is there a way to isolate C++ program from PHP server process? With nohup the process has ppid = 1, so it should be isolated, but it is not.

1
  • consider using a symfony console command ... looks like you´re calling shell_exec() in a controller action which will terminate with terminating the http request AFAIK Commented Apr 20, 2015 at 13:53

2 Answers 2

2

You can look at the Symfony Process Component : http://symfony.com/doc/current/components/process.html

$process = new Process('nohup my/program/written/in/c++.out some arguments');
$process->run();

You will be able to run your process.

Sign up to request clarification or add additional context in comments.

2 Comments

But this waits until the process is finished. Am I right? It is not good for long running processes.
@H.W. You can use $process->start(); to run in background, however if the scripts ends (or, more accurately, if $process destructor is called), then the process will be killed. If your script will definitely have to quit before the process finishes, use something like nohup <your command> (on linux). You'll still have to make sure $process is not garbage collected, so store it somewhere safely. ;)
0

You can create symfony2 console command "myapp:my-command-name" that will run your c++ command

class MyStandaloneCommand extends ContainerAwareCommand
{
    protected function configure()
    {
        $this->setName('myapp:my-command-name')
            ->setDescription('Will run standalone c++')
            ->addArgument('arg1', InputArgument::REQUIRED, 'Some arg');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {   
        $arg1 = $input->getArgument('arg1');
        $result = shell_exec('nohup my/program/written/in/c++.out '.$arg1.' 2>&1');

        $output->writeln('My cool command is started');

        return true;
    }

}

Then use 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;
    }
}

1 Comment

Cool, but it would be cooler to use symfony/process instead of shell_exec(). ;) One known "feature" from that function is that STDOUT and STDERR of the executed program is redirect to the owning PHP process, something most people wouldn't want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.