5

我为我的 symfony2 项目创建了一个控制台命令,我想从控制器执行它而不阻塞控制器输出(在后台)。

通常是这样执行的:

$application = new Application($kernel);
$application->setAutoExit(true);

// AppBundle/Command/UpdateStockCommand.php
      $input = new ArrayInput(array(
          'command' => 'update:stock',
        ));

$output = new NullOutput();
$application->run($input, $output);

但是像这样运行,用户将不得不等待任务完成,这可能需要几分钟。

一个解决方案是:

$kernel = $this->get('kernel');
$process = new \Symfony\Component\Process\Process('nohup php '. $kernel->getRootDir() .'/console update:stock --env='. $kernel->getEnvironment() .' > /dev/null 2>&1 &');
//$process->start();
$process->run();

没有给出错误,控制器呈现输出,但任务没有执行。

另一种解决方案是:

exec('/usr/bin/php '.$this->get('kernel')->getRootDir().'/console update:stock --env=dev > /dev/null 2>&1 &');

在这里找到Symfony2 - 启动 symfony2 命令的进程, 但不适用于我的示例。

4

3 回答 3

2

进程分层

系统中的所有进程都有自己的层次结构。

例如:我们有一个Process A, 启动后我们运行Process B. 如果你杀Process A,那么Process B杀到,因为Process B是孩子Process A

你的问题

每个请求 (http) Apache 创建一个新的子进程来运行 PHP 代码并将标准输出返回给客户端(Nginx + PHPFPM 的逻辑 - 相同)。在创建子进程之后(通过Symfony/Process library),这个进程是 apache 或 fpm 进程的子进程。完成请求后(返回对 apache 或 nginx 的响应),服务器杀死子进程(执行 PHP 代码的地方)。

为您解决方案:

  1. 运行后台命令的好主意 - 使用nohup教程
  2. 对于任何应用程序都有不同的好主意——在进程之间使用AMQP协议。(通过 RabbitMQ 教程

附言

在我的项目中,为了运行后台任务,我使用 RabbitMQ。

于 2016-05-12T10:01:51.987 回答
0

您可以将输出设置为新的 NullOutput。

   $output = new NullOutput();
   $application->run($input, $output);

但最好的办法是使用RabbitMqueue

于 2018-09-19T13:42:57.640 回答
0

让我扩展@CerapuStefan 的解决方案

exec('bash -c "exec nohup setsid '.$this->get('kernel')->getRootDir().'/console update:stock --env=dev > /dev/null 2>&1 &"');

nohup很重要

于 2018-09-19T12:40:02.710 回答