如何在后台通过控制器执行Symfony命令?

问题描述 投票:1回答:1

我有一个需要长时间运行的命令(它会生成一个大文件)。

我想使用一个控制器在后台启动它,而不是等待它的执行结束来渲染一个视图。

这可能吗?如果可以,怎么做?

我想用 流程 类将会很有用,但文档中说:"如果一个Response在子进程完成之前被发送,服务器进程将被杀死(取决于你的操作系统)。

如果在子进程完成之前发送了一个Response,服务器进程将被杀死(取决于你的操作系统)。这意味着你的任务将被立即停止。运行一个异步进程和运行一个在父进程中存活的进程是不一样的。

symfony asynchronous symfony4
1个回答
0
投票

我使用以下方法解决了我的问题 信使组件 正如@msg在评论中建议的那样。

要做到这一点,我必须

  • 安装Messenger组件 composer require symfony/messenger
  • 创建一个自定义的日志实体来跟踪文件的生成。
  • 为我的文件生成创建一个自定义Message和自定义MessageHandler。
  • 在我的控制器视图中发送消息
  • 把我的命令代码移到服务方法中
  • 在我的MessageHandler中调用服务方法。
  • 运行 bin/console messenger:consume -vv 来处理信息

这是我的代码。

自定义日志实体

我用它在我的视图中显示文件是否正在生成,如果文件生成完成,则让用户下载该文件

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\MyLogForTheBigFileRepository")
 */
class MyLogForTheBigFile
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="datetime")
     */
    private $generationDateStart;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $generationDateEnd;

    /**
     * @ORM\Column(type="string", length=200, nullable=true)
     */
    private $filename;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User")
     * @ORM\JoinColumn(nullable=false)
     */
    private $generator;

    public function __construct() { }

    // getters and setters for the attributes
    // ...
    // ...
}

控制器

我收到表单提交并发送一条消息,该消息将运行文件生成功能

/**
 * @return views
 * @param Request $request The request.
 * @Route("/generate/big-file", name="generate_big_file")
 */
public function generateBigFileAction(
    Request $request,
    MessageBusInterface $messageBus,
    MyFileService $myFileService
)
{
    // Entity manager
    $em = $this->getDoctrine()->getManager();

    // Creating an empty Form Data Object
    $myFormOptionsFDO = new MyFormOptionsFDO();

    // Form creation
    $myForm = $this->createForm(
        MyFormType::class,
        $myFormOptionsFDO
    );

    $myForm->handleRequest($request);

    // Submit
    if ($myForm->isSubmitted() && $myForm->isValid())
    {
        $myOption = $myFormOptionsFDO->getOption();

        // Creating the database log using a custom entity 
        $myFileGenerationDate = new \DateTime();
        $myLogForTheBigFile = new MyLogForTheBigFile();
        $myLogForTheBigFile->setGenerationDateStart($myFileGenerationDate);
        $myLogForTheBigFile->setGenerator($this->getUser());
        $myLogForTheBigFile->setOption($myOption);

        // Save that the file is being generated using the custom entity
        $em->persist($myLogForTheBigFile);
        $em->flush();

        $messageBus->dispatch(
                new GenerateBigFileMessage(
                        $myLogForTheBigFile->getId(),
                        $this->getUser()->getId()
        ));

        $this->addFlash(
                'success', 'Big file generation started...'
        );

        return $this->redirectToRoute('bigfiles_list');
    }

    return $this->render('Files/generate-big-file.html.twig', [
        'form' => $myForm->createView(),
    ]);
}

留言内容

用于向服务传递数据


namespace App\Message;


class GenerateBigFileMessage
{
    private $myLogForTheBigFileId;
    private $userId;

    public function __construct(int $myLogForTheBigFileId, int $userId)
    {
        $this->myLogForTheBigFileId = $myLogForTheBigFileId;
        $this->userId = $userId;
    }

    public function getMyLogForTheBigFileId(): int
    {
        return $this->myLogForTheBigFileId;
    }

    public function getUserId(): int
    {
        return $this->userId;
    }
}

信息处理程序

处理该消息并运行服务

namespace App\MessageHandler;

use App\Service\MyFileService;
use App\Message\GenerateBigFileMessage;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;

class GenerateBigFileMessageHandler implements MessageHandlerInterface
{
    private $myFileService;

    public function __construct(MyFileService $myFileService)
    {
        $this->myFileService = $myFileService;
    }

    public function __invoke(GenerateBigFileMessage $generateBigFileMessage)
    {
        $myLogForTheBigFileId = $generateBigFileMessage->getMyLogForTheBigFileId();
        $userId = $generateBigFileMessage->getUserId();
        $this->myFileService->generateBigFile($myLogForTheBigFileId, $userId);
    }
}

服务项目

生成大文件并更新记录仪。

public function generateBigFile($myLogForTheBigFileId, $userId)
{
    // Get the user asking for the generation
    $user = $this->em->getRepository(User::class)->find($userId);

    // Get the log object corresponding to this generation
    $myLogForTheBigFile = $this->em->getRepository(MyLogForTheBigFile::class)->find($myLogForTheBigFileId);
    $myOption = $myLogForTheBigFile->getOption();

    // Generate the file
    $fullFilename = 'my_file.pdf';
    // ...
    // ...

    // Update the log
    $myLogForTheBigFile->setGenerationDateEnd(new \DateTime());
    $myLogForTheBigFile->setFilename($fullFilename);

    $this->em->persist($myLogForTheBigFile);
    $this->em->flush();
}
© www.soinside.com 2019 - 2024. All rights reserved.