使用Symfony Process运行后台任务,而无需等待进程完成

bla*_*elt 13 php symfony

用户提交表单后,我想渲染一个视图文件,然后我想启动一个后台任务来处理五个MS Excel文件(每个文件最多可能有2000行),但是这样就让用户不要不必等待该过程完成才能查看该页面.任务完成后,我将通过电子邮件通知用户.

我正在使用Symfony Framework 3.我在下面包含了我的代码.它没有做我想要实现的目标.提交表单后,页面仅在整个后台任务完成时加载.

我不确定但是经过google搜索后,我认为kernel.terminate事件在这里很有用.但我似乎无法理解如何使用它.

你能告诉我如何解决这个问题吗?

这是我的代码:

我创建了一个控制台命令:

class GreetCommand extends ContainerAwareCommand {

  protected function configure()
  {
    $this->setName('hello:world');
  }

  protected function execute(InputInterface $input, OutputInterface $output)
  {
   // My code to execute
  }

}
Run Code Online (Sandbox Code Playgroud)

在我的控制器中我有

$process = new Process('ls -lsa');
$process->disableOutput();
$that = $this;

$process->start(function ($type, $buffer) use ($that) {
        $command = new GreetCommand();
        $command->setContainer($this->container);
        $input = new ArrayInput(array());
        $output = new NullOutput;
        $resultCode = $command->run($input, $output);

 });

 return $this->render('success.html.php',  array('msg' => 'Registraion Successful'));
Run Code Online (Sandbox Code Playgroud)

更新

我已经使用PHP的连接处理功能解决了这个问题.

感谢这篇文章

Den*_*mov 20

异步运行进程

您也可以启动子进程,然后让它以异步方式运行,在您需要时检索主进程中的输出和状态.使用start()方法启动异步进程

文件

因此,要异步启动命令,您应该使用命令创建新进程并启动它

$process = new Process('php bin/console hello:word');
$process->start();
Run Code Online (Sandbox Code Playgroud)

考虑将此更改为完整路径,例如 \usr\bin\php \var\www\html\bin\console hello:word

还有一个很好的bundle cocur/background-process你可以使用它,或者至少阅读文档以了解它是如何工作的.

  • @black_belt,不。这不是因为你在窗户上。您的主流程是启动流程的应用程序。子进程的输出流附加到主进程,它将阻止应用进程从终止直到子按下完成。 (2认同)
  • 这个答案听起来不对。它在文档中说:“如果在子进程有机会完成之前发送响应,则服务器进程将被终止(取决于您的操作系统)。” 这与问题所要求的相反。 (2认同)

Art*_*lin 6

在控制器中使用:

use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\PostResponseEvent;

$myVar = new MyObject();
$this->get('event_dispatcher')->addListener(KernelEvents::TERMINATE, function(PostResponseEvent $event) use($myVar) {
    //You logic here
    $request = $event->getRequest();
    $test = $myVar->getMyStuff();
});
Run Code Online (Sandbox Code Playgroud)

但这不是一个好习惯,请阅读有关正常注册事件侦听器的信息

kernel.terminate 事件将在向用户发送响应后调度。


小智 6

游戏有点晚了,但我刚刚使用fromShellCommandLine()方法找到了解决此问题的方法

use Symfony\Component\Process\Process;

Process::fromShellCommandline('/usr/bin/php /var/www/bin/console hello:world')->start();
Run Code Online (Sandbox Code Playgroud)

这样就可以异步启动新进程/运行命令。

  • 请注意,这仅在 4.3+ 中可用。 (2认同)

And*_*nko 5

有一个名为AsyncServiceCallBundle的包,它允许您在后台调用服务的方法。

您可以参考答案以获取有关如何在内部完成的更多详细信息。您需要做的就是调用您的服务的方法,如下所示:

$this->get('krlove.async')->call('service_id', 'method', [$arg1, $arg2]);
Run Code Online (Sandbox Code Playgroud)


小智 5

简单使用 Symfony 进程选项

创建新控制台

来自 Symfony 流程来源

 /**
  * Defines options to pass to the underlying proc_open().
  *
  * @see https://php.net/proc_open for the options supported by PHP.
  *
  * Enabling the "create_new_console" option allows a subprocess to continue
  * to run after the main process exited, on both Windows and *nix
  */
  public function setOptions(array $options)
Run Code Online (Sandbox Code Playgroud)

所以让我们这样做:

$process = new Process($cmds);
$process->setOptions(['create_new_console' => true]);
$process->start();
Run Code Online (Sandbox Code Playgroud)