【问题标题】:Symfony2 run console command in backgroundSymfony2 在后台运行控制台命令
【发布时间】:2016-05-11 20:10:55
【问题描述】:

我为我的 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 - process launching a symfony2 command 但不适用于我的示例。

【问题讨论】:

  • console./app 子目录中,还是在./bin 子目录中(较新的symfony 版本) - 如果它在bin 中,那么您需要更新控制台命令的路径。另外,$process->isSuccessful()run() 之后返回什么?
  • 另外,如果你在shell命令行中运行nohup php PATH/console update:stock --env=ENV > /dev/null 2>&1 &,任务运行是否成功?
  • 控制台位于 app 文件夹中(我使用 symfony v2.8)。该命令在腻子中运行正常,但是有一个问题,如果我在运行命令后按任意键,它将终止该进程......我认为这是问题所在,因为我已经为输出放置了一个文本文件(而不是/dev/null),它显示了控制器的输出,它是一个 json 响应。
  • 嗯我不明白,如果你在 putty 中运行命令,它应该启动命令并在后台运行它,你应该立即得到 shell (putty) 命令提示符。你是说,如果你按任意键,在命令提示符下它会停止在后台运行命令?
  • 米罗,是的,没错。对我来说也很奇怪。你可以自己测试一下。

标签: symfony background-process symfony-process


【解决方案1】:

进程分层

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

例如:我们有一个Process A,在它启动后我们运行Process B。如果你杀死Process A,那么Process B 被杀死,因为Process BProcess A 的孩子。

你的问题

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

为您提供解决方案:

  1. 运行后台命令的好主意 - 使用 nohup (tutorial)
  2. 适用于任何应用程序的不同好主意 - 在进程之间使用AMQP 协议。 (tutorial via RabbitMQ)

附言

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

【讨论】:

  • 对于第一个解决方案。我已经启动了进程 B 并且我正在运行的命令正在使用 nohup,但是如果进程 B 被杀死,我是否使用 nohup 都没关系,对吧?
  • @CeparuStefan,对不起,我不知道,因为我没有在我的项目中使用 nohup。我只在进程之间使用 AMQP 协议。
【解决方案2】:

让我扩展@CerapuStefan 的解决方案

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

nohup 很重要

【讨论】:

  • 最后,谢谢你。我正在努力从 fcgi 开始一个独立的控制台工作。
【解决方案3】:

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

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

不过最好还是用RabbitMqueue

【讨论】:

    猜你喜欢
    • 2013-08-08
    • 1970-01-01
    • 2014-02-23
    • 2012-07-20
    • 1970-01-01
    • 2013-10-19
    • 1970-01-01
    • 2014-12-17
    • 2021-11-27
    相关资源
    最近更新 更多