我有一个需要长时间运行的命令(它会生成一个大文件)。
我想使用一个控制器在后台启动它,而不是等待它的执行结束来渲染一个视图。
这可能吗?如果可以,怎么做?
我想用 流程 类将会很有用,但文档中说:"如果一个Response在子进程完成之前被发送,服务器进程将被杀死(取决于你的操作系统)。
如果在子进程完成之前发送了一个Response,服务器进程将被杀死(取决于你的操作系统)。这意味着你的任务将被立即停止。运行一个异步进程和运行一个在父进程中存活的进程是不一样的。
我使用以下方法解决了我的问题 信使组件 正如@msg在评论中建议的那样。
要做到这一点,我必须
composer require symfony/messenger
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();
}