tags:

views:

80

answers:

5

Anyone know how to close the connection (besides just flush()?), but keep executing some code afterwards. I don't want the client to see the long process that may occur after the page is done.

THANK YOU!

+6  A: 

You might want to look at pcntl_fork() -- it allows you to fork your current script and run it in a separate thread.

I used it in a project where a user uploaded a file and then the script performed various operations on it, including communicating with a third-party server, which could take a long time. After the initial upload, the script forked and displayed the next page to the user, and the parent killed itself off. The child then continued executing, and was queried by the returned page for its status using AJAX. it made the application much more responsive, and the user got feedback as to the status while it was executing.

This link has more on how to use it: https://sites.google.com/a/van-steenbeek.net/archive/php_pcntl_fork

If you can't use pcntl_fork, you can always fall back to returning a page quickly that fires an AJAX request to execute more items from a queue.

Jhong
note that you can only use pcntl_fork() (in this context) with a custom made http server written in php itself - so typically this response can only be used about 0.0001% of the time ;)
nathan
I was using Apache.
Jhong
Then you fork the entire apache daemon I think. That's not a pretty sight, and probably not the intended use of an apache module...
mvds
I believe it forks the apache worker process, of which the process would be one of many (albeit way too many by default). That, coupled with the fact that the average linux server is pretty good at forking processes, leads me to expect it is not as problematic as you might expect. My experience was not for a mission-critical app though.As I say though, this is only the minor part of the solution -- the main architecture of the solution is setting up the client - server model properly.
Jhong
+4  A: 

I don't want the client to see the long process that may occur after the page is done.

sadly, the page isn't done until after the long process has finished - hence what you ask for is impossible (to implement in the way you infer) I'm afraid.

The key here, pointed to by Jhong's answer and inversely suggested by animusen's comment, is that the whole point of what we do with HTTP as web developers is to respond to a request as quickly as possible /end - that's it, so if you're doing anything else, then it points to some design decision that could perhaps have been a little better :)

Typically, you take the additional task you are doing after returning the 'page' and hand it over to some other process, normally that means placing the task in a job queue and having a cli daemon or a cron job pick it up and do what's needed.

The exact solution is specific to what you're doing, and the answer to a different (set of) questions; but for this one it comes down to: no you can't close the connection, and one would advise you look at refactoring the long running process out of that script / page.

nathan
+1  A: 

Don't fork the entire apache webserver, but start a separate process instead. Let that process fork off a child which lives on. Look for proc_open to get full fd interaction between your php script and the process.

mvds
A: 

Take a look at php's 'ignore_user_abort' setting. You can set it using the ignore_user_abort() function.

Also, take a look at this comment:

http://www.php.net/manual/en/features.connection-handling.php#93441

And the one below it:

http://www.php.net/manual/en/features.connection-handling.php#89177

Arctic Fire
+1  A: 

We solved this issue by inserting the work that needs to be done into a job queue, and then have a cron-script pick up the backend jobs regularly. Probably not exactly what you need, but it works very well for data-intensive processes.

(you could also use Zend Server's job queue, if you've got a wad of cash and want a tried-and-tested solution)

kander