One ajax call block other ajax call - php

Once my page is loaded, I perform an Ajax call to a php script, which updates my server. However this script can sometimes take over a minute to complete, and while the script is running, I am unable to perform other Ajax calls, which I need to handle - i.e the first Ajax call should not interrupt the other Ajax calls. Any idea how to do this?
First Ajax call:
$(document).ready(function () {
$.ajax({
url: "checkForUpdatesByCoach.php",
success: function(arg){
if(arg == "200"){
$('body').prepend("<div style='text-align:center;margin-bottom:-12px;' onClick='location.reload()' class='alert alert-success'>Dine hold er blevet opdateret.Tryk for at opdatere!</div>").fadeIn("slow");
}
}
});
});
Second Ajax call (a user triggered call):
$.ajax({
type: "POST",
data: {data:dataAjax},
url: "updateSwimmer1.php",
success: function(arg){
//updating UI
}
});

adeno's comment above is correct.
"in PHP only one script at a time can operate on the same session, so
as to not overwrite session data etc. So when doing two ajax calls to
PHP scripts within the same session, the second has to wait for the
first to finish"
to help speed things up you can write to and end a session early(session_write_close()) to release the session-lock and allow another script using the session to continue.
note: you can still read from your $_SESSION variable after calling session_write_close but you may no longer write to it.
you can find a good example of this here: PHP Session Locks – How to Prevent Blocking Requests
example provided from the link above:
<?php
// start the session
session_start();
// I can read/write to session
$_SESSION['latestRequestTime'] = time();
// close the session
session_write_close();
// now do my long-running code.
// still able to read from session, but not write
$twitterId = $_SESSION['twitterId'];
// dang Twitter can be slow, good thing my other Ajax calls
// aren't waiting for this to complete
$twitterFeed = fetchTwitterFeed($twitterId);
echo json_encode($twitterFeed);
?>

Related

Progress during AjaX call displays only initial and final value

I need to execute an AjaX call to a PHP script with a long execution time. My goal is to display a progress status of this execution.
The idea is to create an AjaX call to periodically ask the server about the status of the execution. The progress status is stored into $_SESSION['progress'], initially set to 0 and changed from script during execution.
Here's my code on client and server side.
Client-side
// invoke the script (ie. with button)
$('#start').click(function()
{
$.ajax
({
url: "long-script.php"
});
});
// check progress periodically
setInterval(progress, 100);
function progress()
{
$.ajax
({
dataType: "json",
url: "progress.php",
success: function(data)
{
console.log(data);
}
});
}
long-script.php
// just an example to emulate execution
sleep(1);
$_SESSION['progress']=30;
sleep(1);
$_SESSION['progress']=70;
sleep(1);
$_SESSION['progress']=100;
progress.php
header('Content-Type: application/json');
echo json_encode($_SESSION['progress']);
The problem is that console.log() in progress function outputs 0 before the script execution, stops outputing data during the execution, and finally outputs 100 when the script is terminated. What am I missing?
The problem is that the session is not written, until the script ends, or the session closes.
You need to remember that sessions, by default in php are stored as files on the system and is locked in run-time.
What you can do is change the long-script.php file a bit.
session_start();
sleep(1);
$_SESSION['progress']=30;
session_write_close();
sleep(1);
session_start();
$_SESSION['progress']=70;
session_write_close();
sleep(1);
session_start();
$_SESSION['progress']=100;
session_write_close();
The idea is to write to the session after every progress changes.
Then you will need to start the session again.
This may be a wrong way to do this, but you can always look up the session functions in php. Take a look at this session_write_cloe

Multiple ajax requests at the same time

I have a form that is validated then submitted with the following handler :
submitHandler:function (form) {
$.ajax({
url: 'long_process.php',
type: 'POST',
data: $(form).serialize(),
success: function (result) {
// ... Redirect ...
}
});
//start polling
(function poll() {
setTimeout(function () {
$.ajax({
url: "get_progress.php",
success: function (data) {
console.log(data);
//Setup the next poll recursively
poll();
},
});
}, 3000);
})();
}
long_process.php takes about 30s to finish and in the meantime I'd like to track the progress via get_progress.php which echo the percentage of processing done.
When launching this script I get in the console (edited):
1 POST long_process.php
2 GET get_process.php (3 seconds later)...
...stuck here until long_process.php finishes THEN
3 GET get_process.php (3 seconds later)...
4 GET get_process.php (3 seconds later)...
...
but none of the get_progress.php return any values until the long_process.php is finished.
How can I achieve multiple simultaneous ajax request ? Ultimately this will be used to display a progress bar.
If you are using sessions in your PHP then the one call will block the other, because PHP won't allow two requests to use the same session space at the same time. Your two requests are probably firing, but you are not getting a request to the second until the server finishes with the first.
To solve this:
Option 1: Don't use sessions in the first script that you are calling or, if you must, then unlock the session using session_write_close(). After calling this, of course, you can't write any session variables.
Option 2: If reading and writing session variables is essential then don't use session variables in the second AJAX call and don't declare a session start. Have your first script put it's status somewhere else for you to read (in a DB, a file on /tmp) and then have the second script read the status from there.
Hope that helps!

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 request remains pending

I have made a simple chat application which uses long-polling approach using jquery,
function sendchat(){
// this code sends the message
$.ajax({
url: "send.php",
async: true,
data: { /* send inputbox1.value */ },
success: function(data) { }
});
}
function listen_for_message(){
// this code listens for message
$.ajax({
url: "listen.php",
async: true,
timeout:5000,
success: function(data) { // the message recievend so display that message and make new request for listening new messages
$('#display').html(data);
listen_for_message();
}
});
}
THIS SHOULD HAPPEN : after page loaded the infinite request for listen.php occurs and when user sends message, the code sends message to database via send.php.
PROBLEM is, using firebug i've found that send.php request which is performed after listen.php request, is remains pending. means the request for send message is remains pending.
The issue was because of session locking;
both send.php and listen.php files use session variables,
so session is locked in listen.php file and the other file (here send.php file) can't be served after the session frees from serving another file ( here listen.php).
How do I implement basic "Long Polling"?
the link above is a similar question that may help you.
it does not have to be on a database, it can be saved on a tmp file, but your problem is that you are choking the browser by performing too many requests, any one browser handles two requests at a time, which means you should really allow the browser to finish the first requests first then do the second one... and so on...
you do not need to do send.php and listen.php, because you can do it simply on one page both of them.
function check(){
$.ajax({
url : 'process.php',
data : {msg:'blabla'/* add data here to post e.g inputbox1.value or serialised data */}
type : 'post',
success: function (r){
if(r.message){
$('#result').append(r.message);
check();//can use a setTimeout here if you wish
}
}
});
}
process.php
<?php
$msg = $_POST['msg'];//is blabla in this case.
$arg['message'] = $msg;//or grab from db or file
//obviously you will have to put it on a database or on a file ... your choice
//so you can differentiate who sent what to whom.
echo json_encode($arg);
?>
obviously this are only guide lines, but you will exhaust your bandwidth with this method, however it will be alot better because you have only one small file that returns either 0 to 1 byte of information, or more if there is a message posted.
I have not tested this so don't rely on it to work straight away you need a bit of changes to make it work but just helps you understand how you should do it.
however if you are looking for long pulling ajax there are loads of scripts out there already made and fine tuned and have been test, bug fixed and many minds help built it, my advice is don't re-invent the wheel

php ajax window close problem

i have a php web application, where i use an authentication method. I have a script logout.php in the same directory as the index file.
I want that the code in the logout.php be executed if the used mid session decides to exit or navigate away from the page.
ive tried using
function closeIt()
{
var exit = confirm("Are you sure you want to end this chat session ?");
if(exit==true){
$.ajax({
type: "GET",
url: "logout.php",
success: function(){ alert("Done");}
});
}
}
window.onbeforeunload = closeIt;
i get the confirm box,
but i am not getting success, am i doing somethign worng or do i need a new approach all together ?
The Ajax call is performed asynchronously, so the call is made and processing is passed back to the page immediately, which then closes before the ajax call completes.
You need to make a synchronous call to make this work.
A in AJAX stands for asynchronous. You may want to use synchronous XMLHttpRequest or return false at the end of closeIt() (that should prevent closing window) and in your success function, change onbeforeunload to null and close the window with window.close()

Categories