Reputation: 333
I have this function set to run at intervals using JavaScript which points to a PHP page. I was just wondering if this is bad practice for the server load, especially at scale.
The PHP page just retrieves data from the Slack API through CURL and just echoes it out back.
setInterval(function(){
$.post('slackAPI.php?',function(data){
//append data received to some class
}, 'html');
}, 100);
This option works perfectly but I'm worried that it'll cause a heavy load on the server, is there a better option to retrieve data from an API in real time?
Upvotes: 1
Views: 1408
Reputation: 57418
Your server load stems from two sources:
Depending on the scenario you can improve either of them (or even both):
If a third-party information is likely to be updated no oftener than 'x', you can store the call's result into a database, memory keystore, or cache file, and read its contents if it's still "fresh".
Even better, you can use GET to retrieve the datum, and issue appropriate Expires
header from the PHP side. This will prevent most AJAX libraries from issuing unnecessary calls. Of course, you now run the risk of not retrieving immediately a fresh information that came by in the meantime:
// 30 seconds timeout
Header('Expires: '.gmdate('D, d M Y H:i:s \\G\\M\\T', time() + 30));
Instead of using a fixed interval, if you can whip up an API that waits for data to come, you can put the updating function as a callback of the updating function itself.
This way, you will issue a POST that will take, say, from 100 to 20000 milliseconds to complete. Before it completes, there is no data, so it would have been useless to issue 199 other calls to the same API in the meanwhile. When it completes, it immediately fires off a new AJAX call, which will wait again, and so on. This is better done with a jQuery Promise loop; writing it in straight Javascript would result in a recursive function, and there's a limit on how many recursions you can enter.
Another advantage is that you can control the client update frequency from the server.
You would do this using setTimeout
, not setInterval
.
function refresher() {
$.get('/your/api/endpoint', { maxtimeout: 30 })
.then(function(reply) {
if (reply.changes) {
// ...update the UI? Here you call your "old" function.
}
// Immediately issue another call, which will wait.
window.setTimeout(refresher, 1);
});
}
// Call immediately. The return callback will wait.
refresher();
The best option is the third:
Most such poll services have the possibility of either issuing a long-blocking call (the one you would use above) or to register an URL which will receive the data when there's data to be fetched. Then you store the information and cache it, while the receiving endpoint on the server keeps the cache updated. You now only have to worry about the inbound calls, which are quickly handled.
The inbound call could then block and wait, consuming very few resources:
// $cacheFile is written by the callback API entry point
$ms = 200; // Granularity is 200 milliseconds
$seconds = 30; // Max linger time is 30 seconds (could be higher)
$delay = floor(($seconds * 1000.0) / $ms);
while ($delay--) {
// filemtime must read up-to-date information, NOT stale.
clearstatcache(false, $cacheFile);
if (filemtime($cacheFile) !== $lastCreationTime) {
break;
}
usleep($ms * 1000);
}
Header('Content-Type: application/json;charset=UTF-8');
readfile($cacheFile);
die();
The above will have a overhead of 150 stat()
calls (30 seconds, 5 calls per second), which is absolutely negligible, and will save 149 web server calls and all related traffic and delays.
Upvotes: 3