2015-04-20 1 views
1

Я использую Symfony2, и я хочу запустить длинный скрипт, написанный на C++ (например, 60 минут).Symfony выполнение сценария с длинным сценарием

Теперь я делаю это с помощью shell_exec():

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

Если я буду освежать страницу скрипт работает нормально, но если я иду AFK сценарий завершается процесс PHP сервера (/ USR/BIN/PHP -cgi).

Есть ли способ изолировать C++-программу от процесса PHP-сервера? С nohup процесс имеет ppid = 1, поэтому он должен быть изолирован, но это не так.

+0

Рассмотрите возможность использования команды консоли symfony ... похоже, что вы вызываете shell_exe c() в действии контроллера, который завершится с завершением HTTP-запроса AFAIK –

ответ

2

Вы можете посмотреть на процесс компонента Symfony: http://symfony.com/doc/current/components/process.html

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

Вы сможете запустить процесс.

+1

Но это ждет, пока процесс не завершится. Я прав? Это не хорошо для длительных процессов. –

+0

@ H.W. Вы можете использовать '$ process-> start();' для запуска в фоновом режиме, однако, если скрипты заканчиваются (или, точнее, если вызывается деструктор '' $ process' (https://github.com/symfony/ process/blob/3.0/Process.php # L172)), тогда процесс будет убит. Если ваш скрипт обязательно должен выйти до завершения процесса, используйте что-то вроде 'nohup ' (on linux). Вам все равно придется убедиться, что '$ process' не собирает мусор, поэтому храните его где-то безопасно. ;) – Christian

0

Вы можете создать команду Symfony2 консоли "MyApp:-командное имя моего", который будет работать ваш C++ команды

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

} 

Затем используйте 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

Прохладный, но было бы круче использовать 'symfony/process' вместо' shell_exec() '. ;) Одна известная «особенность» этой функции заключается в том, что STDOUT и STDERR исполняемой программы перенаправляются на собственный PHP-процесс, чего большинство людей не захочет. – Christian