When a long-running PHP file is executing, and the user cancels the page request in their browser midway, is the rest of the script ran on the server?
PHP normally terminates script execution once it realizes that the connection is closed:
PHP will not detect that the user has aborted the connection until an
attempt is made to send information to the client. Simply using an
echo statement does not guarantee that information is sent, see
flush().
You can keep your script running using ignore_user_abort().
Also, there is a default time limit for which scripts are allowed to run. You may want to override that using set_time_limit().
I tested this once on a long running process and discovered that the script will continue to run once it has not exceeded the maximum time to execute.
For me (using XAMPP on an older computer), cancelling the web page in the middle of an operation meant to process one million primary records, with a couple of other tables being updated in the process, the MySQL database operations kept going, which tells me that the PHP script kept running on the server. By "cancelling," I mean clicking the stop button on the tab, but not closing the tab altogether. BTW: I had established set_time_limit() to 0 to keep the script from timing out before completing in absence of cancelling.
Related
I was wondering - as I wrote a snippet of code that could update up to 10,000 rows and might take a few seconds to complete, if when the file is accessed via an ajax request, the post query is send to the php file, then the browser is closed, does the file get fully executed? assume it takes about 25 seconds to complete the request, the user might not wait for 25 seconds, is good enough to "ping" this file and let the user browse along or close its browser window as the mysql queries are taking place?
The request has 3 parts
A browser connected to the web server
PHP script that is executed by the server
A query running in the DB server
When you close the browser, connection with the server is closed. The server may or may not kill the started PHP script (if PHP is running as apache module, it would be killed, unless ignore_user_abort is called). Also the web server may have a time limit for the request and either kill the script or just send the client a connection timeout message, without killing the script, but without giving it the chance to send anything to the browser.
Here is the tricky part - the update is running in the database and it won't be killed by the web server, neither by PHP.
So what you want to achieve is pinging a PHP script, that is executing a query, but the client do not wait the result. You may or may not want the query itself to be asyncronous (the PHP script not to wait the query), but you have to tell the client that the request is fulfilled, by sending content-length of 0 for example, and flushing the output (the http headers actually), and running PHP with ignore_user_abort so it continues the execution.
Use ignore-user-abort to continue running the script even after the client has disconnected
ignore_user_abort(true);
set_time_limit(0);
You can use connection_status to track if the connection has disconnected
if (connection_status()!=0) { //connection disconnected
Here's the answer for your question:
http://www.php.net/manual/en/features.connection-handling.php
Normally no, but your script pass in ABORTED status.
More details in the manual page about Connection handling:
http://www.php.net/manual/en/features.connection-handling.php
Internally in PHP a connection status is maintained. There are 3
possible states:
0 - NORMAL
1 - ABORTED
2 - TIMEOUT
When a PHP script is running normally the NORMAL state, is active. If
the remote client disconnects the ABORTED state flag is turned on. A
remote client disconnect is usually caused by the user hitting his
STOP button.
As soon as you close the browser, it disconnects from the server before getting the reply. I do not know exactly how different servers behave in this condition but I assume that most of the server will abort the thread that they are working on to reply the request.
Further, things can be different with different operations - i.e. file i/o or database operation. If it is an atomic database operation, my assumption is, it will complete any how.
I have an action that occurs when a user goes to a url. The action involves a tremendous amount of insert-update ot a MYSQL database and takes a good minute to finish. I was wondering if this action continues even if a user switches to another page? I would expect so since PHP is server side. But i would like to have a clear explanation on this. Anyone?
No, the default operation of Apache and PHP is to terminate the script when the user disconnects. This termination can happen anytime after the connection is broken, so your script may run for hours, or could die instantly. Generally the kill occurs when the script attempts to do any output.
If you need to keep the script running in spite of user disconnects, then you'll have to use
ignore_user_abort(TRUE);
I'm using transactions in a MySQL database, along with Ajax, and I'm having some troubles with scripts timing out. So, here's a rundown of what happens:
Ajax script on page makes request to server.
Server receives request; script starts a MySQL transaction.
Ajax script is set to timeout after two seconds; times out; tells server to abort request.
Server script dies; transaction is left hanging.
MySQL notices transaction has been left hanging; rolls back as it's supposed to, but not before a bunch of customers become less than happy because the tables were locked for half a minute and they couldn't access the website.
What to do?
I imagine the server script just needs a bit more time than the two seconds it's given, so I called ignore_user_abort() on every page, and then called register_shutdown_function() to explicitly roll back a transaction if the client has in fact aborted.
Is this a good plan? Is there an alternative?
register_shutdown_function() by itself would even be a good solution. Try removing the ignore_user_abort() so that the script knows when (or if) the users aborts the loading.
I would also probably let the script have more than 2 seconds of a time out, see if this helps.
Are you using persistent database connections, ie: using mysql_pconnect()? Those will keep the connection alive within the web server even when no PHP script is running. As such, any transactions/locks acquired during the script's run will be left active within that persistent connection when the script shuts down abnormally.
Even if your scripts normally clean up after themselves with mysql_close(), any abnormal termination will leave that persistent connection up. And stay up until the connection is re-used from the pool and properly shut down by some other script.
For example, there is a very simple PHP script which updates some tables on database, but this process takes a long time (maybe 10 minutes). Therefore, I want this script to continue processing even if the user closed the browser, because sometimes users do not wait and they close the browser or go to another webpage.
If the task takes 10 minutes, do not use a browser to execute it directly. You have lots of other options:
Use a cronjob to execute the task
periodically.
Have the browser
request insert a new row into a
database table so that a regular
cronjob can process the new row and
execute the PHP script with the
appropriate arguments
Have the
browser request write a message to
queue system, which has a subscriber
listening for such events (which then
executes the script).
While some of these suggestions are probably overkill for your situation, the key, combining feature is to de-couple the browser request from the execution of the job, so that it can be completed asynchronously.
If you need the browser window updated with progress, you will need to use a periodically-executed AJAX request to retrieve the job status.
To answer your question directly, see ignore_user_abort
More broadly, you probably have an architecture problem here.
If many users can initiate this stuff, you'll want the web application to add jobs to some kind of queue, and have a set number of background processes that chew through all the work.
The PHP script will keep running after the client terminates the connection (not doing so would be a security risk), but only up to max_execution_time (set in php.ini or through a PHP script, generally 30 seconds by default)..
For example:
<?php
$fh = fopen("bluh.txt", 'w');
for($i=0; $i<20; $i++) {
echo $i."<br/>";
fwrite($fh,$i."\n");
sleep(1);
}
fclose($fh);
?>
Start running that in your browser and close the browser before it completes. You'll find that after 20 seconds the file contains all of the values of $i.
Change the upper bound of the for loop to 100 instead of 20, and you'll find it only runs from 0 to 29. Because of PHP's max_execution_time the script times out and dies.
if the script is completely server based (no feedback to the user) this will be done even if the client is closed.
The general architecture of PHP is that a clients send a request to a script that gives a reply to the user. if nothing is given back to the user the script will still execute even if the user is not on the other side anymore. More simpler: their is no constant connection between server and client on a regular script.
You can make the PHP script run every 20 minutes using a crontab file which contains the time and what command to run in this case it would be the php script.
Yes. The server doesn't know if the user closed the browser. At least it doesn't notice that immediately.
No: the server probably (depending of how it is configured) won't allow for a php script to run for 10 minutes. On a cheap shared hosting I wouldn't rely on a script running for longer than a reasonable response time.
A server-side script will go on what it is doing regardless of what the client is doing.
EDIT: By the way, are you sure that you want to have pages that take 10 minutes to open? I suggest you to employ a task queue (whose items are executed by cron on a timely basis) and redirect user to a "ok, I am on it" page.
I want to run a relatively time consuming script based on some form input, but I'd rather not resort to cron, so I'm wondering if a php page requested through ajax will continue to execute until completion or if it will halt if the user leaves the page.
It doesn't actually output to the browser until a json_encode at the end of the file, so would everything before that still execute?
It depends.
From http://us3.php.net/manual/en/features.connection-handling.php:
When a PHP script is running normally
the NORMAL state, is active. If the
remote client disconnects the ABORTED
state flag is turned on. A remote
client disconnect is usually caused by
the user hitting his STOP button.
You can decide whether or not you want
a client disconnect to cause your
script to be aborted. Sometimes it is
handy to always have your scripts run
to completion even if there is no
remote browser receiving the output.
The default behaviour is however for
your script to be aborted when the
remote client disconnects. This
behaviour can be set via the
ignore_user_abort php.ini directive as
well as through the corresponding
php_value ignore_user_abort Apache
httpd.conf directive or with the
ignore_user_abort() function.
That would seem to say the answer to your question is "Yes, the script will terminate if the user leaves the page".
However realize that depending on the backend SAPI being used (eg, mod_php), php cannot detect that the client has aborted the connection until an attempt is made to send information to the client. If your long running script does not issue a flush() the script may keep on running even though the user has closed the connection.
Complicating things is even if you do issue periodic calls to flush(), having output buffering on will cause those calls to trap and won't send them down to the client until the script completes anyway!
Further complicating things is if you have installed Apache handlers that buffer the response (for example mod_gzip) then once again php will not detect that the connection is closed and the script will keep on trucking.
Phew.
It depends on your settings - usually it will stop but you can use ignore_user_abort() to make it carry on.
Depending on the configuration of the web server and/or PHP, the PHP process may, or may not, kill the thread when the user terminates the HTTP connection. If an AJAX request is pending when the user walks away from the page, it is dependent on the browser killing the request (not guaranteed) ontop of your server config (not guaranteed). Not the answer you want to hear!
I would recommend creating a work queue in a flat file or database that a constantly-running PHP daemon can poll for jobs. It doesn't suffer from cron delay but keeps CPU/memory usage to a usable level. Once the job is complete, place the results in the flat file/database for AJAX fetch. Or promise to e-mail the user once the job is finished (my preferred method).
Hope that helps
If the client/user/downloader/viewer aborts or disconnects, the script will keep running until something tries do flush new data do the client. Unless you have used
ignore_user_abort(), the script will die there.
In the same order, PHP is unable to determine if client is still there without trying to flush any data to the httpd.
found the actual solution for my case of it not terminating the connection. The SESSION on my Apache/Php server needed to close before the next one could start.
Browser waits for ajax call to complete after abort.