Why is KernelEvents::TERMINATE blocking the response to the user?

梦想的初衷 提交于 2019-12-13 02:07:51

问题


In a Silex application running on HVVM I have setup a dummy event listener on Kernel TERMINATE:

$app['dispatcher']->addListener(
    KernelEvents::TERMINATE,
    function () use ($app) {
        usleep(10000000);
        $app['logger']->alert("I AM REGISTERED!");
    }
);

I was expecting my application to render the response as fast as possible within a second and after 10s I expected the message "I AM REGISTERED" to appear in my log.

Yet strangely the response is sent after the event has been executed, meaning the event blocks the response for 10s and I see both the response and the log message at the same time.

What is going on here?

I find it odd that in the Application.php, it appears that send is called before 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);
}

回答1:


The symfony2 docs about HttpKernel, which silex is uisng as well, it says:

Internally, the HttpKernel makes use of the fastcgi_finish_request PHP function. This means that at the moment, only the PHP FPM server API is able to send a response to the client while the server's PHP process still performs some tasks. With all other server APIs, listeners to kernel.terminate are still executed, but the response is not sent to the client until they are all completed.

And fastcgi_finish_request is not currently supported by hhvm.

Hence, the response will not be sent unless all events are completed.




回答2:


  1. PHP is not asynchronous, so while event handling is possible through use of callbacks, as soon as the event triggers, the control flow of the process will be dedicated to it.

  2. Frameworks tend to delay content response to be the last action taken, in case any form of header modification has to happen.

As you mentioned, the content is being sent/echoed before the TERMINATE event is fired, but that's not the whole story.

It depends on how your server is set up. If, for example, you have gzip enabled in apache (very common), then apache will cache all content until PHP has finished execution (and then it will gzip and send it). You mentioned that you're on HHVM, which could also be the problem - it might not flush the content itself until execution is complete.

Either way, the best solution is to... well... not sleep. I'm assuming that you're sleeping to give the database a chance to flush to disk (10 seconds is a really long time to wait for that, though). If that's not the case, then finding a decent solution won't be easy until we can understand why you need to wait that long.



来源:https://stackoverflow.com/questions/34002455/why-is-kerneleventsterminate-blocking-the-response-to-the-user

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!