在HVVM上运行的Silex应用程序中,我在内核TERMINATE
上设置了一个虚拟事件监听器:
$app['dispatcher']->addListener(
KernelEvents::TERMINATE,
function () use ($app) {
usleep(10000000);
$app['logger']->alert("I AM REGISTERED!");
}
);
我希望我的应用程序能够在一秒钟内尽快呈现响应,并且在10秒后我希望消息"I AM REGISTERED"
出现在我的日志中。
然而奇怪的是,响应是在事件执行后发送的,这意味着事件会阻止响应10秒,同时我会看到响应和日志消息。
这里发生了什么?
我觉得奇怪的是,在Application.php中,似乎send
之前调用了terminate
:
vendor/silex/silex/src/Silex/Application.php
:
/**
* Handles the request and delivers the response.
*
* @param Request|null $request Request to process
*/
public function run(Request $request = null)
{
if (null === $request) {
$request = Request::createFromGlobals();
}
$response = $this->handle($request);
$response->send();
$this->terminate($request, $response);
}
答案 0 :(得分:1)
symfony2 docs about HttpKernel
,也就是说,它也是一种,它说:
在内部,HttpKernel使用fastcgi_finish_request PHP 功能。这意味着目前只有PHP FPM服务器API 能够在服务器的PHP时向客户端发送响应 进程仍然执行一些任务。使用所有其他服务器API, kernel.terminate的监听器仍然执行,但响应是 在他们全部完成之前不会发送给客户。
而fastcgi_finish_request
是not currently supported by hhvm。
因此,除非所有事件都已完成,否则不会发送回复。
答案 1 :(得分:1)
PHP不是异步的,因此虽然可以通过使用回调来处理事件,但只要事件触发,该过程的控制流就会专用于它。
如果必须进行任何形式的标题修改,框架往往会将内容响应延迟为最后采取的操作。
正如您所提到的,在TERMINATE
事件被触发之前,内容正在被发送/回显,但这不是全部。
这取决于您的服务器的设置方式。例如,如果你在apache中启用了gzip(很常见),那么 apache 将缓存所有内容,直到PHP完成执行(然后它将gzip并发送它)。你提到你在HHVM上,这也可能是问题 - 它可能不会在执行完成之前刷新内容。
无论哪种方式,最好的解决方案是......好吧......不要睡觉。我假设你正在睡觉,让数据库有机会刷新到磁盘(10秒是很长时间等待它)。如果情况并非如此,那么找到一个合适的解决方案会很容易,直到我们理解为什么你需要等待那么久。