How to continue a script after AJAX response is sent to user?

After receiving an AJAX request, I want to give feedback to the user before the PHP script finishes, because it takes long.

I thought that the send() method of the yii\web\Response object was made for that, so I tried the following inside the controller action:




Yii::$app->response->format = Response::FORMAT_JSON;

Yii::$app->response->data = [ 'success' => $someData ];

Yii::$app->response->send();


// code that takes long

sleep(5);



The response is sent, but after sleeping for 5 seconds.

Same luck with:




ob_start();

echo json_encode([ 'success' => $someData ]);

header('Connection: close');

header('Content-Type: application/json');

header('Content-Length: '.ob_get_length());

ob_end_flush();

flush();


// code that takes long

sleep(5);



I didn’t have any confidence in this last code working inside a controller action, but I had it in the first one… what am I missing?

I like fastcgi_finish_request().

This is a really a PHP question, not a Yii question, so I expect you can find lots of answers on SO, perhaps some of them even correct!

Thank you fsb, luckily I’m using PHP-FPM, so fastcgi_finish_request() is available and works flawlessly.




Yii::$app->response->format = Response::FORMAT_JSON;

Yii::$app->response->data = [ 'success' => $someData ];

Yii::$app->response->send();


fastcgi_finish_request();


// code that takes long

sleep(5);



I have already tried it on SO :), anyway I was looking for a Yii way to achieve it.

Following the docs (sorry, this is my first post and I’m not allowed to provide links)

[quote name=’/doc-2.0/guide-runtime-responses.html#sending-response’]The content in a response is not sent to the user until the yii\web\Response::send() method is called. By default, this method will be called automatically at the end of yii\base\Application::run(). You can, however, explicitly call this method to force sending out the response immediately.
[/quote]

I had a look to the source code and response->send() is actually flushing the content, so I was expecting it to work. Is it the expected behaviour to need fastcgi_finish_request() after Yii::$app->response->send() ?

I can’t find the OB flush you refer to. But in any case, flushing the output buffer is not enough to disconnect the PHP script from the client connection and cause the web server to finish up its response to the client.

But you got me interested now. Could the framework provide a convenient way to do this, e.g. send($andDisconect = false), that’s more-or-less portable across web servers?

Maybe you’d like to add this as a feature request.

You are right, there is neither ob_end_flush nor ob_flush(), just flush(). It looks like send() method is not supposed to finish the job.

I thought that it was a nice idea so I digged a little more into the topic and it seems that it is too environment dependant.

In a related issue in GH (#8923) the core team considered that this kind of stuff is not to be fixed in the framework.

Anyway, maybe a wiki article about how to achieve it for different environments could be valuable. Obviously this is not my field, but I would happily help with test & review if someone start it.