PHP Symfony Silex,在finish()之前不发送响应


PHP Symfony Silex, response is not sent before finish()

我要做的是:用户进行API调用,我给出响应,然后我开始执行耗时较长的操作,例如发送电子邮件。(电子邮件需要很长时间,因为我使用SMTP,所以swiftmailer是以同步的方式发送的。)

根据文档,finish()应该在发送响应后调用。然而,当我对此进行测试时,情况似乎并非如此。我的客户端一直在等待finish()完成。

服务器端代码:

$app = new Silex'Application();
$app->get('/hello', function (Request $r) use($app) {
    return $app->json("I should load within a few milliseconds.");
});

$app->finish(function() use () {
    //Pretend to do some slow action afterwards
    sleep(5);
});
$app->run();

现在,如果我加载页面http://localhost/hello,它将需要5秒才能加载。而我的期望是它会立即加载。我是不是误解了文件?

更新:

从技术上讲,公认的答案符合我的要求。实际上,我找到了一个不同的解决方案:

我一直在寻找一种方法,让我的电子邮件以一种最终用户不必等待的方式发送。出于我的目的,我切换到使用Swift_MailTransport而不是Swift_SmtpTransport,并在本地将exim4配置为智能主机。通过这种方式,电子邮件被转交给Exim4,脚本立即继续。

如果你正在寻找除电子邮件之外的其他长流程来执行,请查看Beanstalk等消息队列,我读到了关于它们的精彩内容。

下面接受的答案确实有效(也可以按照文档页面评论中的链接),但我发现解决方案对于我的特定情况来说不够干净。

我是不是误解了文件?

不,你没有。web响应的内容在finish过滤器运行之前发送,但输出未刷新。尝试添加

 ob_flush();
 flush();

sleep(5)之前,它将如您所期望的那样工作。

您可能想要像SwiftmailerBundle那样伪造电子邮件。请参阅swiftmailer.use_spool.

默认情况下,Swiftmailer提供商使用KernelEvents::TERMINATE事件,在响应已发送。