how to show Ajax request progress - php

I have this ajax request to update my db.
function ajax_submit(){
var submit_val=$("#stato").serialize();
dest="plan/new_bp1.php";
$.ajax({
type: "POST",
url: dest,
data: submit_val,
success: function(data){
data1=data.split("|");
if(data1[0]=="Successo"){
$("#spnmsg").fadeTo(200,0.1,
function(){$(this).removeClass().addClass("spn_success").html(data1[1]).fadeTo(900,1)});
}else if(data1[0]=="Errore"){
$("#spnmsg").fadeTo(200,0.1,
function(){$(this).removeClass().addClass("spn_error").html(data1[1]).fadeTo(900,1)});
}
},
complete: function(){
setTimeout(function(){ $('.container').load('plan/home.php');},2000);
}
});
}
The called script will take long to perform since it has to select, elaborate and insert around 4.000 recors each time. What I do now is to add a spinner on the screen to give users a feedback that the request is working (triggered by AjaxStart and AjaxStop).
At the end of the call the complete function will echo what the php script will echo.
What I'd like to do is to have a counter that will update during the script execution where I can say something like "X records out of 4.000 processed"
On the script side I have no problem to calculate the number of processed records and the number of record overall.
How can I update my script to show the progress?

You have a couple of options.
1) Right when the request starts you can start polling a different endpoint that just serves out the number of records that have been processed, like #adeneo suggested. You don't have to write to a file every time a record is processed. You can just store it in memory and ensure that the route handler you have to handle requests coming in for the progress has access to that same memory.
2) Implement a websocket endpoint on your server that pushes out the number of processed records. Basically, on the server then, you will call that Websocket library code to push out the progress. You will also have to create a Websocket connection on the Javascript side, which is trivial, and listen for those messages.

Related

php and ajax: show progress for long script

I have php script which can take quite a lot of time (up to 3-5 minutes), so I would like to notify user how is it going.
I read this question and decided to use session for keeping information about work progress.
So, I have the following instructions in php:
public function longScript()
{
$generatingProgressSession = new Zend_Session_Namespace('generating_progress');
$generatingProgressSession->unsetAll();
....
$generatingProgressSession->total = $productsNumber;
...
$processedProducts = 0;
foreach($models as $model){
//Do some processing
$processedProducts++;
$generatingProgressSession->processed = $processedProducts;
}
}
And I have simple script for taking data from session (number of total and processed items) which return them in json format.
So, here is js code for calling long script:
$.ajax({
url: 'pathToLongScript',
data: {fileId: fileId, format: 'json'},
dataType: 'json',
success: function(data){
if(data.success){
if(typeof successCallback == "function")
successCallback(data);
}
}
});
//Start checking progress functionality
var checkingGenerationProgress = setInterval(function(){
$.ajax({
url: 'pathToCheckingStatusFunction',
data: {format: 'json'},
success: function(data){
console.log("Processed "+data.processed+" items of "+data.total);
if(data.processed == data.total){
clearInterval(checkingGenerationProgress);
}
}
});
}, 10000)
So, long scripted is called via ajax. Then after 10 seconds checking script is called one time, after 20 second - second time etc.
The problem is that none of requests to checking script is completed until main long script is complete. So, what does it mean? That long script consumes too many resources and server can not process any other request? Or I have some wrong ajax parameters?
See image:
-----------UPD
Here is a php function for checking status:
public function checkGenerationProgressAction()
{
$generatingProgressSession = new Zend_Session_Namespace('generating_progress');
$this->view->total = $generatingProgressSession->total;
$this->view->processed = $generatingProgressSession->processed;
}
I'm using ZF1 ActionContext helper here, so result of this function is json object {'total':'somevalue','processed':'another value'}
I'd
exec ('nohup php ...');
the file and send it to background. You can set points the long running script is inserting a single value in DB to show it's progress. Now you can go and check every ten or whatever seconds if a new value has been added and inform the user. Even might be possible to inform the user when he is on another page within your project, depending on your environment.
Yes, it's possible that the long scripts hogs the entire server and any other requests made in that time are waiting to get their turn. Also i would recommend you to not run the check script every 10 seconds no matter if the previous check has finished or not but instead let the check script trigger itself after it has been completed.
Taking for example your image with the requests pending, instead of having 3 checking request running at the same time you can chain them so that at any one time only one checking request is run.
You can do this by replacing your setInterval() function with a setTimeout() function and re-initialize the setTimeout() after the AJAX check request is completed
Most likely, the following calls are not completing due to session locking. When one thread has a session file open, no other PHP threads can open that same file, as it is read/write locked until the previous thread lets go of it.
Either that, or your Server OR Browser is limiting concurrent requests, and therefore waiting for this one to complete.
My solution would be to either fork or break the long-running script off somehow. Perhaps a call to exec to another script with the requisite parameters, or any way you think would work. Break the long-running script into a separate thread and return from the current one, notifying the user that the execution has begun.
The second part would be to log the progress of the script somewhere. A database, Memcache, or a file would work. Simply set a value in a pre-determined location that the follow-up calls can check on.
Not that "pre-determined" should not be the same for everyone. It should be a location that only the user's session and the worker know.
Can you paste the PHP of "pathToCheckingStatusFunction" here?
Also, I notice that the "pathToCheckingStatusFunction" ajax function doesn't have a dataType: "json". This could be causing a problem. Are you using the $_POST['format'] anywhere?
I also recommend chaining the checks into after the first check has completed. If you need help with that, I can post a solution.
Edit, add possible solution:
I'm not sure that using Zend_namespace is the right approach. I would recommend using session_start() and session_name(). Call the variables out of $_SESSION.
Example File 1:
session_name('test');
session_start();
$_SESSION['percent'] = 0;
...stuff...
$_SESSION['percent'] = 90;
Example File 2(get percent):
session_name('test');
session_start();
echo $_SESSION['percent'];

jQuery Ajax: how to wait until *async* requests success

I am calling one jquery ajax request in my PHP code. This code fetch the data from database and export into the excel file. Once ajax request will success, i will get excel file popup download box. This feature is working fine in all browser.
Now, problem is when that jquery request is taking more time (7-8 minutes), excel file is created on the server, but download box is not popup and after 30 minutes i am getting timeout error.
what could be the problem, file is created on the server in 7 minutes but i am not getting any response from ajax request. I am also checked the timeout for ajax request it is set for 30 minutes.
Even if you manage to solve the timeout, making your clients wait 7 to 8 minutes without any progress feedback will be far from ideal. Better way would be to initiate the export on the server and return immediately. Once this returns you can give a progress message that says 'Export in progress..' or something. Then you can have an AJAX call that periodically checks the status of the export and returns the appropriate status message. Once exporting is done, you can change the progress feedback to 'Export complete: Download file' with Download file being a link to the excel file created on the server. you can also trigger a click on that link via code to automatically start the download.
i.e.
Assuming you have a DIV with class status which shows the export status
First AJAX call to initiate the export:
$.post({
url: '/export/',
...
success: function(data) {
$('.status').html('Export in progress. Please wait...');
}
});
Second AJAX call to poll export progress
$.post({
url: '/exportstatus/',
...
success: function(data) {
if(data=='OK') {
$('.status').html('Export complete: <a class="exportedfile" href="/path/to/exported/file">Download File</a>');
setTimeout(function() {
$('.status').find('a').click(); // trigger autostart of download
}, 1000);
}
}
});
You're doing it wrong: you don't want to force a user to be stuck on a page for more than a few seconds at most in order to get service from your app.
Instead, use a widget that will periodically query a status page (with ajax, of course) and display a message when the job is done.
(What kind of excel file is taking 7 minutes to generate? A db dump?)
Edit:
Different browsers will behave differently with long ajax requests, so don't depend on them waiting around forever even if the user is willing to. Your app will be much more robust if you decouple requesting a report generation and downloading the report.
This should give you an idea of what I'm talking about:
create_my_excel_file.php:
$_SESSION['excel_status']='generating';
create_the_excel_file();
$_SESSION['excel_status']='finished';
check_status.php:
echo $_SESSION['excel_status'];
user_interface.php:
<script type="text/javascript">
function initiateRequest(){
$.ajax('create_my_excel_file.php');
setInterval('checkForCompletion()', 5000);
}
function checkForCompletion(){
$.get('check_status.php', function(data){
if('finished'==data){
alert('Completed! Download the file now.');
location.href='file_download.php';
}
});
}
</script>
Generate the file

PHP and jQuery: Return incremental results as search runs

I need to process a very long running process in PHP (grepping big text files and returning matching lines). When we run an average query from the command line, the process may take 10-15m.
I wanted to implement in PHP/jQuery, whereby I started the query, then showed incremental results as they came back.
I implemented something close, where I had one ajax call doing the search (worked fine), and had a periodic timer function running calling a second method in the class to get the results. However, I realized that the 2nd call would really create a new class instance, so the $this->current was different between the main query and the period update timer.
Here's the javascript I was trying (I was kicking it off when clicking a form button):
<script>
function update_status(data) {
alert(data);
jQuery.each(data, function(key, val) {
if ( key == "progress" )
$("#progressbar").progressbar({ value: val });
});
}
function progress_setup() {
setInterval(function() {
jQuery.ajax({
type:'POST',
dataType:'json',
complete:function(XMLHttpRequest, textStatus){
update_status(textStatus)
},
url:'<?php echo url_for("#grep_status"); ?>'
})},
2000);
}
function grep(elements) {
jQuery.ajax({
type:'POST',
dataType:'html',
data:jQuery(elements).serialize(),
success:function(data, textStatus){jQuery('#results').html(data);},
beforeSend:function(XMLHttpRequest){progress_setup()},
url:'/grep'});
}
</script>
But, this doesn't appear to be the right track. The core issue seems to be:
Long running task in PHP
How do you get the status of that task back to a progress bar, and an incremental results dialog?
TIA
Mike
You have to share the state of your operation either using a database or a file. Then in your /grep operation you periodically write the state in the database or the file (updating the state).
Then you need another script (like /grep_state) which reads the state and returns it to the client.
What you can't do is share the state using a PHP-object instance since this it's scope is limited to a single request. You have to persist the state.
The other Problem might be that your long running task is terminated because of a request timeout either by the webserver or the browser. I would either run the script in CLI-mode (detached from the webserver/request) or write a simple job-scheduler which runs as a daemon.
The daemon gets the parameters from a socket (or any other means of communicating with other processes) and starts the php-CLI with your worker-script. The state is also shared using files or a database.
Seems like the easiest thing to do is to split the task up in php and send some sort of flag back to your client side app to tell it when it's finished.
Maybe:
Get the size of the file.
Begin the query, return the first result with a character number.
Update progress bar.
Start next query beginning at last character number, return second result with character number.
Update progress bar.
Continue until reached end of file.
Although that wouldn't give you a perfect progress update, it would indicate how far you've searched into the file.
I think the key is to set up your server with parameters that allow you to limit/filter your query results.
You can try flushing your output early--this varies according to your server settings, however. For example:
// Script starts, does first block of program
echo "1";
flush();
// Second block starts and finishes
echo "2";
flush();
// Etc...
After each block completes, flush a response.

javascript autoupdate when a sql record is changed (or equals some specific value)

Is it possible for javascript to update automatically if a mySQL field is modified? I'm assuming this basically translates to some kind of a constant query of a specific SQL record.
For an example, lets suppose I'm making a simple /multiplayer/ tic-tac-toe using PHP and jquery with a mySQL background.
I want the tic-tac-toe page to be powered by jquery so that the user does not have to do a page refresh.
Two users get hooked up and the game begins. User 2 waits while user 1 thinks about where to put an X. When User 1 clicks a square to include an X, I'd like for user 2 to have their screen automatically changed to reflect - without having to press any buttons to check for updates.
You could poll the server every X seconds (say 10 seconds) via AJAX to check if it's changed. Theres no (easy) way of pushing data to the client side.
Example code:
function checkStatus() {
setTimeout('checkStatus()',10000);
$.ajax({
url: "checkStatus.php",
    success: function(data){
      //Code to handle change goes here
    }
  });
}
setTimeout('checkStatus()',10000);
You have two main solutions, polling or websockets(which isn't fully supported in all browsers btw), both involve communicate with the backend. I'm not going to cover websockets, however it is an up and coming technology that keeps an open connections from the frontend to the backend. Another option is using something like Comet, which allows you to keep an HTTP connection open for a long time.
The other solution you have is polling, in which you make an ajax request every x seconds to "poll" for changes.
This could be done using Ajax (use JQuery Ajax). It could refresh every couple of seconds to update the page with the latest content from the database. This approach is fine on a small scale with a low a number users but is very draining on your server's resources as it is constantly sending and receiving data even if new data is not available.
A better option may be to use node.js and socket.io to support large scale real time processes.
Yes - one way is to use a long-polling comet. Essentially, this works by making an asynchronous (typically with AJAX) request from the server and waiting for the response. The wait can be for an hour, say. When it receives a response, it 'completes' the request and then sends another request in the same way.
There are lots of other ways though - check out 'push technology'.
I'd been trying to use setTimeout but had no success. I used setInterval and it seems to work like a charm.
Code follows:
function waitForMsg(){
$.ajax({
url: "tictac_code1.php",
type: 'POST',
data: 'longpoll=1',
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:10000, /* Timeout in ms */
success: function(data){ /* called when request to barge.php completes */
$('#loggedinnames').empty();
$('#loggedinnames').append(data);
setInterval(waitForMsg, 10000);
//setTimeout(
// 'waitForMsg()', /* Request next message */
// 1000 /* ..after 1 seconds */
//);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
//alert("error in waitformsg.");
addmsg("error", textStatus + " (" + errorThrown + ")");
setInterval(waitForMsg, 10000);
//setTimeout(
// 'waitForMsg()', /* Try again after.. */
// "15000"); /* milliseconds (15seconds) */
}
});
};
$(document).ready(function(){
waitForMsg(); /* Start the inital request */
});

Handling successive Ajax requests - JQUERY

I have a search textbox where upon a keypress an AJAX call is made to return search results for the entered text. This results in an AJAX call being made for every single keypress.
For example if I type in airport:
I get 7 ajax requests each searching for a, ai, air, airp, airpo, airpor, airport respectively - however the problem is that they might all start one after the other but don't necessarily end in the same order so more often than not I receive results in the wrong order i.e I might have written airport and received the result for airport only to receive the result for airpo later on.
How do I handle this in jQuery here?
Update:
There is a timer delay of 3 seconds - but the issue is in ensuring that when one AJAX request is made, another Request when made cancels out the previous request and so forth.
How could I do this in code?
Fire the ajax call on a delay - use this in conjunction with the abort() code above:
var typeDelay = function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
}
}();
$("#searchField").keypress(function(){
typeDelay(function(){
// your ajax search here, with a 300 ms delay...
}, 300);
});
Sending a lookup request at every keystroke is generally a bad idea - I'd suggest instead that you send at short intervals (ie. send the textbox value every 3 seconds or so).
Further, to prevent the asynchronous returns, you could have a flag to keep track of a request's state, so that only 1 can be active at any one time (eg. set on send, cleared on return). This would effectively render your lookups synchronous.
EDIT: Added sample code
var req = null;
function sendRequest (text)
{
// Check for pending request & cancel it
if (req) req.abort ();
req = $.ajax ({
// various options..
success: function (data)
{
// Process data
...
// reset request
req = null;
}
});
}
You can cancel AJAX requests:
var x = $.ajax({
...
});
x.abort()
So if you want to send a new request before the previous one has returned, abort() the first one.
Build an "ajax queue" in jquery... use it to ensure your requests go in order. The below address has a great example near the bottom:
AJAX Streamlining techniques?
Extend the functionality of these queue, to handle Delay and Abort mechanics like the answers above.
If another request is submitted to the queue before the delay is over, abort the queued request.
Suggestion: add the functionality of delay and abort mechanics properly to the queue so that the values can be requested when you post a request to the queue, like params, that way your queue plugin remains reusable outside this need.

Categories