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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37733820/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 01:21:34  来源:igfitidea点击:

Running a background task using Symfony Process without having to wait for the process to finish

phpsymfony

提问by black_belt

After a user submits a form, I want to render a view file, and right after that I want to initiate a background task to process five MS Excel files (each may have up to 2000 rows) , but in way so that the user don't have to wait for the process to finish in order to view the page. After the task is finished I will inform the user through an email.

用户提交表单后,我想呈现一个视图文件,然后我想启动一个后台任务来处理五个 MS Excel 文件(每个文件最多可能有 2000 行),但以某种方式让用户不不必等待过程完成才能查看页面。任务完成后,我会通过电子邮件通知用户。

I am using Symfony Framework 3. I have included my code below. Its not doing what I am trying to achieve. After submitting the form the page loads only when the entire background task is complete.

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

I am not sure but after googling a lot, I think The kernel.terminate Eventcould be useful here. But I can't seem to understand how to work with it.

我不确定,但经过大量谷歌搜索后,我认为kernel.terminate 事件在这里可能很有用。但我似乎无法理解如何使用它。

Could you please tell me how to solve this problem ?

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

Here's my code:

这是我的代码:

I have created a Console Command:

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

class GreetCommand extends ContainerAwareCommand {

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

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

}

And in my controller I have

在我的控制器中,我有

$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'));

Update

更新

I have solved the problem using the connection-handling feature of PHP.

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

Thanks to this post

感谢这篇文章

回答by Denis Alimov

Running Processes Asynchronously

You can also start the subprocess and then let it run asynchronously, retrieving output and the status in your main process whenever you need it. Use the start() method to start an asynchronous process

异步运行进程

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

documentation

文件

so, to start your command asynchronously you should create new process with command and start it

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

$process = new Process('php bin/console hello:word');
$process->start();

Consider to change this to full paths like \usr\bin\php \var\www\html\bin\console hello:word

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

Also there is good bundle cocur/background-processyou may use it, or at least read the docs to find out how it works.

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

回答by Arthur Khusnullin

For using in controller:

在控制器中使用:

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

But it is not a good practice, please read about normal registering event listeners

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

kernel.terminate event will be dispatched after sending the response to user.

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

回答by r.vanlaarhoven

I guess what you want is to store the necessary data in a database and then have a cronjob/queue execute the actual command, instead of trying to execute it directly from your controller.

我想您想要的是将必要的数据存储在数据库中,然后让 cronjob/队列执行实际命令,而不是尝试直接从控制器执行它。

Add something like the following to your /etc/crontab to let it run your command every 5 minutes

将以下内容添加到您的 /etc/crontab 中,让它每 5 分钟运行一次您的命令

*/5 * * * * root /usr/bin/php /path/to/bin/console hello:world

Then, let your command query the database for the stored data and have it process the excel files

然后,让您的命令查询数据库中存储的数据并让它处理 excel 文件

回答by Andrey Mischenko

There is a bundle called AsyncServiceCallBundlewhich allows you to call your service's methods in background.

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

You can refer thisanswer for more details about how it is done internally. Everything you need is to invoke your service's method as follows:

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

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

回答by Michal

I am a bit late to the game, but I just found a solution for this problem using the fromShellCommandLine()method:

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

use Symfony\Component\Process\Process;

Process::fromShellCommandline('/usr/bin/php /var/www/bin/console hello:world')->start();

This way it is possible to start a new process/run a command asynchronously.

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