I want to make a progress bar on my website, which tracks execution of a PHP script.
The PHP script makes a bunch of connections with Google API and stores the data it receives in the database. Sometimes the process can take a minute.
The PHP script is located in ajax/integrations-ajax.php
file and launched by GET AJAX request sent, if on the website to click #link
button. Below is jQuery code for the request:
$('#link').on('click', function () {
var interval = setInterval(trackStatus, 1000);
$.getJSON('ajax/integrations-ajax.php', {action: 'link'}).done(function (json) {
if (json.result == true) {
showMessage('The account is successfully linked.', 'success');
} else {
showMessage('There is an error happened.', 'danger');
}
})
});
This #link
button, also sets interval which fires trackStatus
function each second:
function trackStatus() {
$.getJSON('ajax/status-ajax.php', {
action: 'status'
}).done(function (json) {
console.log(json.status);
});
}
As you can see, trackStatus
function sends GET AJAX requests to ajax/status-ajax.php
file and should show status in browser console every second.
To implement tracking ability on the server I made the PHP script in ajax/integrations-ajax.php
file to store status in the database. Its code you can see below:
<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'link') {
set_status_in_database(0);
// some execution code;
set_status_in_database(1);
// some execution code;
set_status_in_database(2);
// some execution code;
set_status_in_database(3);
// some execution code;
echo json_encode(['result' => true ]);
}
And created another PHP file axax/status-ajax.php
which can recover the status from the database:
<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'status') {
$return['result'] = get_status_from_database();
echo json_encode($return);
}
But the requests appear not to be working simultaneously. I can't receive responses for trackStatus
function until the response on completion ajax/integrations-ajax.php
script isn't received.
I made a profiling record in browser, which show that:
So, is there a possibility to execute requests simultaneously? Or to implement the tracking ability I need to rethink the whole approach?
Thanks in advance for help!
Update Thank you all for your advice! And especially to @Keith, because his solution is the easiest and works. I have put session_write_close() function in the beginning for the script and everything works:
<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'link') {
session_write_close();
set_status_in_database(0);
// some execution code;
set_status_in_database(1);
// some execution code;
set_status_in_database(2);
// some execution code;
set_status_in_database(3);
// some execution code;
echo json_encode(['result' => true ]);
}
Here you can see profiling record from a browser:
How many concurrent AJAX (XmlHttpRequest) requests are allowed in popular browsers? Bookmark this question. Show activity on this post. In Firefox 3, the answer is 6 per domain: as soon as a 7th XmlHttpRequest (on any tab) to the same domain is fired, it is queued until one of the other 6 finish.
AJAX allows web pages to be updated asynchronously by exchanging small amounts of data with the server behind the scenes. This means that it is possible to update parts of a web page, without reloading the whole page. Classic web pages, (which do not use AJAX) must reload the entire page if the content should change.
PHP creates and outputs the Content to the Client Browser as it's a Server-Side Language and that's what it was built for, so on a request your code will access database, files etc. and then output the constructed html/text to the client. Ajax just gives the User a more Desktop like feel.
While PHP can handle concurrent requests without issue, one area that does get serialized is the Session, basically PHP during a request will place an exclusive lock on the SESSION, for that user. IOW: While this lock is on, other requests from the same user will have to wait. This is normally not an issue, but if you have long running requests it will block other requests, like AJax requests etc.
As a default PHP will write session data at then end off the request,. But if you are sure you no longer need to write any session data, calling session_write_close
will release the lock much sooner.
More info here -> http://php.net/manual/en/function.session-write-close.php
Would advise trying EventSource. Here is an example.
PHP
<?php
header('Content-Type: text/event-stream');
// recommended to prevent caching of event data.
header('Cache-Control: no-cache');
function send_message($id, $message, $progress) {
$d = array('message' => $message , 'progress' => $progress);
echo "id: $id" . PHP_EOL;
echo "data: " . json_encode($d) . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
for($i=0; $i<4; $i++){
set_status_in_database($i);
// some execution code;
send_message($i, "set status in database " . $i + 1 . " of 3' , $i*4);
sleep(1);
}
send_message('CLOSE', 'Process complete');
?>
JavaScript
var es;
function startTask() {
es = new eventSource('ajax/status-ajax.php');
es.addEventListener('message', function(e) {
var result = JSON.parse(e.data);
console.log(result.message);
if(e.lastEventId == 'CLOSE') {
console.log('Received CLOSE closing');
es.close();
showMessage('The account is successfully linked.', 'success');
} else {
$('.progress').css("width", result.progress + '%');
}
});
es.addEventListener('error', function(e) {
console.log('Error occurred', e);
es.close();
});
}
function stopTask() {
es.close();
console.log('Interrupted');
}
$('#link').on('click', function(e) {
e.preventDefault();
startTask($(this));
});
Reference:
Hope that is useful for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With