Reputation: 75
I have a forum (in PHP with Symfony2 framework) and I want something really close to real time notifications. What I want more specifically is that when a user receives a private message, a notification appears. I've tried to use the long polling technique, but I have a problem.
So, I send an ajax call from javascrip to php. PHP receives it and makes a query to database to see if there are any new notifications for the user requested by the ajax. If it finds something, it returns that result, else sleeps x seconds. This is happening in a while(true) condition. The problem is that if it doesn't find something, it sleeps, then searches again, and again it sleeps and so on, and while this happens nothing else works. If I try to reload the page, click on something from the forum, read a topic, and so on, all are blocked waiting for that ajax call to finish. What can I do to make that ajax call run in parallel with everything else, or unblock the server while the ajax isn't finished.
This is what I have in javascript:
function poll() {
$.ajax({
type: "post",
url: url to the action from controller,
async: true,
data: { 'userId': $('#userId').attr('data-value') },
dataType: "json",
success: function(result) {
call method to display the notification(s) to the user
setTimeout(poll, 5000);
}
});
};
$(document).ready(function(){
poll();
});
And here is the action from Symfony2 controller:
public function checkForNewNotificationsAction($userId) {
while (true) {
/** @var \Forum\CoreBundle\Entity\Notification[] $notifications */
$notifications = query the database
if ($notifications != null) {
return new JsonResponse($notifications);
} else {
sleep(5);
}
}
}
I have also tried to call a regular PHP file with "pure" PHP code thinking that the action from controller and how Symfony2 manages the controllers is blocking my other activities, but it does exactly the same.
I'm trying to not use any other "tools" like Node.js with Socket.io or something like this because I never worked with them and really don't have time to study. The project must be done in a few days, and still have a lot to do. Also I'm trying to avoid simple ajax calls every x seconds, leaving this as my last option.
Upvotes: 1
Views: 2070
Reputation: 1391
This is natural because the script is acquiring a lock on the session.
Add a session_write_close();
to the beginning of the Ajax action so the lock is released.What you're basically doing is tell php, you're not gonna write into the session anymore so release the lock, this way concurrent requests can be handled.Be careful not to write into the session after making this call.
Official source: session_write_close()
symfony's SessionInterface
has a save
method, which in turn calls session_write_close()
, you should use that instead of session_write_close
.e.g:
$request->getSession()->save();
When you want to write to the session again, you should call SessionInterface::start
.
Upvotes: 2
Reputation: 5520
A "qucik and dirty way" of "solving" this:
Instead of actually doing a request to the database in your PHP-code, you could do something like this:
Why I say "solving" this is that it doesn't actually solve the problem, but it would make it far quicker because it's (usually) quciker to read a file than access a database. On the other hand you might have to face issues with file-locking - depending on how many request we are talking about.
Do it the right way!
There is no "quick way" of solving your problem and I would really recommend you to read up on long pulliing request and websockets. It really doesn't seem that hard using sockets.IO and is a way better solution than above - Here's how to create a chat-application (and its kind of simple to understand what's going in the code): http://socket.io/get-started/chat/
HTML5 websockets isn't available in all browsers, but socketIO (that uses html5 websockets) takes care of that for you and uses long pulling-technique instead when websockets is not available.
Example with jquery and socketIO: https://gist.github.com/anandgeorge/2814934
Another reference that might help: http://techoctave.com/c7/posts/60-simple-long-polling-example-with-javascript-and-jquery
Upvotes: -1
Reputation: 3870
Try this.
var myvar = setInterval(function () {checkForNewNotificationsAction($userId)}, 5);
public function checkForNewNotificationsAction($userId) {
while (true) {
/** @var \Forum\CoreBundle\Entity\Notification[] $notifications */
$notifications = query the database
if ($notifications != null) {
clearInterval(myVar);
return new JsonResponse($notifications);
}
}
}
Upvotes: 0
Reputation: 61222
what if you let the PHP return immediately and change the JavaScript to something like this? At least you could do stuff.
function poll() {
$.ajax({
type: "post",
url: url to the action from controller,
async: true,
data: { 'userId': $('#userId').attr('data-value') },
dataType: "json",
success: function(result) {
//call method to display the notification(s) to the user
//if (problem) {pollForever = false;}
}
});
};
var pollForever;
$(document).ready(function(){
pollForever = true;
while (pollForever) {
setTimeout(poll, 5000);
}
});
Upvotes: 0