在我们的应用程序中,对于某些操作,我们会向相当多的用户(数百到数千)发送通知和电子邮件。出于某些目的,我们必须使用foreach循环单独发送这些电子邮件/通知。 对于大约200-300个用户,这个工作正常,但是一旦有更多用户被通知,我们会在一段时间后暂停。
我现在想要做的是,重定向到新页面,例如创建一个文档,并通过发送20个电子邮件来处理发送到那里的电子邮件/通知,然后显示更新,例如“已发出20个xxx电子邮件/通知”,然后继续发送下一个20,显示更新等等。
是否有任何机构已经做过类似的事情或对此有想法? 到目前为止,这是我的代码:
{
document gets created...
$em->persist($document);
$em->flush();
$this->addFlash(
'success',
'Your document has been created!'
);
return $this->redirectToRoute('documentBundle_document_send_notifications', array('id' => strtok($document->getId(), '_')));
}
/**
* @Route("/document/sendNotifications/{id}", name="documentBundle_document_send_notifications", requirements={"id" = "\d+"})
*/
public function sendDocumentNotifications($id){
$em = $this->getDoctrine()->getManager();
$document = $em->getRepository('DocumentBundle:Document')->findOneById($id);
$statusRepository = $em->getRepository('DocumentBundle:Status');
/*
* NOTIFICATION MANAGEMENT
*/
//Users
$user = $em->getRepository('UserBundle:User');
$user = $user->findByDocumentAgency($user, $document);
$users = array_unique($user->getResult());
if(count($users)>0){
/*
* SEND NOTIFICATION
*/
foreach ($users as $user){
$manager = $this->get('mgilet.notification');
$notif = $manager->generateNotification('A Document has been created!');
$manager->addNotification($user, $notif);
}
/*
* SEND EMAIL
*/
foreach ($users as $user){
$recipient = $user->getEmail();
$this->get('MailerHelper')->sendMessage($recipient,...);
}
}
}
return $this->redirectToRoute('documentBundle_document_list');
}
修改
添加了一个控制台命令以作为后台进程运行
/**
* @Route("/document/sendNotifications/{id}", name="documentBundle_document_send_notifications", requirements={"id" = "\d+"})
*/
public function sendDocumentNotifications($id){
$em = $this->getDoctrine()->getManager();
$document = $em->getRepository('DocumentBundle:Document')->findOneById($id);
$process = new Process('php app/console app:send-notifications', $id );
$process->run();
dump($process);
return $this->redirectToRoute('documentBundle_document_bulkDeactivate');
}
转储进程时,我得到了正确的commandLine,输入是正确的文档ID,但它说:
Process {#1539 ▼
-callback: null
-commandline: "php app/console app:send-notifications"
-cwd: "/srv/http/sp/web"
-env: null
-input: "320"
-starttime: 1511378616.9664
-lastOutputTime: 1511378616.9852
-timeout: 60.0
-idleTimeout: null
-options: array:2 [▼
"suppress_errors" => true
"binary_pipes" => true
]
-exitcode: 1
-fallbackStatus: []
-processInformation: array:8 [▼
"command" => "php app/console app:send-notifications"
"pid" => 29887
"running" => false
"signaled" => false
"stopped" => false
"exitcode" => 1
"termsig" => 0
"stopsig" => 0
然后我尝试了 $ process-> mustRun()并输出以下错误:
命令“php app / console app:send-notifications”失败。
退出代码:1(一般错误)
工作目录:/ srv / http / sp / web
输出: ================无法打开输入文件:app / console
错误输出:
500内部服务器错误 - ProcessFailedException
答案 0 :(得分:0)
TL; DR:为了防止超时,将您的流程卸载到后台进程。
快速获胜将是to Spool Emails:
当您使用SwiftmailerBundle发送电子邮件时 Symfony应用程序,它将默认立即发送电子邮件。 但是,您可能希望避免性能损失 Swift Mailer和电子邮件传输之间的通信 可能会导致用户在电子邮件中等待下一页加载 正在发送。
实际邮件将由命令行脚本发送:
php bin/console swiftmailer:spool:send --env=prod
。
了解如何create a console command。像这样的东西(没有经过测试,只是作为一个例子):
class NotificationCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
// the name of the command (the part after "bin/console")
->setName('app:send-notifications')
// the short description shown while running "php bin/console list"
->setDescription('Send notifications to information users about a new document.')
->addArgument('document', InputArgument::REQUIRED, 'The ID of the new document.')
;
}
public function execute(InputInterface $input, OutputInterface $output)
{
$em = $this->getContainer()->get('doctrine')->getManager();
$document = $em->getRepository('DocumentBundle:Document')->findOneById($input->getArgument('document'));
$statusRepository = $em->getRepository('DocumentBundle:Status');
/*
* NOTIFICATION MANAGEMENT
*/
//Users
$user = $em->getRepository('UserBundle:User');
$user = $user->findByDocumentAgency($user, $document);
$users = array_unique($user->getResult());
if(count($users)>0){
/*
* SEND NOTIFICATION
*/
foreach ($users as $user){
$manager = $this->get('mgilet.notification');
$notif = $manager->generateNotification('A Document has been created!');
$manager->addNotification($user, $notif);
}
/*
* SEND EMAIL
*/
foreach ($users as $user){
$recipient = $user->getEmail();
$this->get('MailerHelper')->sendMessage($recipient,...);
}
}
}
}
}
要执行此操作,请在命令行上运行bin/console app:send-notifications 1
。
我想您不想手动登录服务器来发送通知,因此您可以创建一个可以由cron作业安排的常规“发送通知(如果需要)”命令。
下一步,您可以查看排队命令的方法。以JMSJobQueueBundle为例。
尝试让控制器更薄。阅读this旧的,但仍然有趣的博客。如果您创建服务并从控制器调用它们(而不是使用 fat </ em>控制器),那么将代码从控制器移除到后台作业(反之亦然)的“重构”工作要容易得多。< / p>