如何从控制器在后台执行Symfony命令

LucileDT

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

我想使用一个控制器在后台启动它,而不必等待其执行结束以呈现视图。

可能吗?如果是,怎么办?

我虽然Process类会很有用,但是文档说:

如果在子进程有机会完成之前发送响应,则服务器进程将被终止(取决于您的操作系统)。这意味着您的任务将立即停止。运行异步进程与运行在其父进程中幸存的进程不同。

LucileDT

我使用Messenger组件(如注释中的@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();
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章