I am developing online chat between users on my website. Chat is working properly, but nobody can enter the website if long poll connection is open.
My code [updated]:
$time = $_GET['time'];
while (true) {
$sth = $db->prepare("SELECT * FROM messages LEFT JOIN users ON users.username=messages.chat_msg_user_id WHERE chat_msg_client_id=:chat_msg_client_id AND chat_msg_id>:chat_msg_id AND chat_notification='0' ORDER BY chat_msg_time DESC LIMIT 1");
$sth->execute([":chat_msg_client_id" => $client_id, ":chat_msg_id" => $last_message_id]);
$messages = [];
while ($answer = $sth->fetch()) {
$msg = ["chat_msg_id" => $answer["chat_msg_id"], "chat_msg_user_id" => $answer["chat_msg_user_id"], "chat_username" => $answer['username'], "chat_user_photo" => $answer['mainphoto'], "chat_user_status" => $answer['status'], "chat_user_name" => $answer["name"], "chat_msg_from" => $answer['chat_msg_from'], "chat_msg_time" => date("H:i", $answer["chat_msg_time"]), "chat_msg_date" => date("m.d.y", $answer["chat_msg_time"]), "chat_msg_text" => mb_str_replace("\n", "<br>", $answer["chat_msg_text"]), "read" => $answer['chat_read'], ];
$messages[] = $msg;
$last_message_id = $answer["chat_msg_id"];
// some variables here for json_encode below //
}
if (count($messages) > 0) {
$sth2 = $db->prepare("SELECT count(chat_read) as unread_messages_count FROM messages WHERE chat_msg_client_id='$client_id' AND chat_read='0'");
$sth2->execute();
$answers = $sth2->fetch();
$unread_messages_count = $answers['unread_messages_count'];
echo json_encode(["command" => "new_messages", "messages" => $messages, "last_message_id" => $last_message_id, "chat_msg_id" => $chat_msg_id, "chat_user_name" => $chat_user_name, "chat_user_status" => $chat_user_status, "chat_user_photo" => $chat_user_photo, "chat_msg_from" => $chat_msg_from, "chat_msg_time" => $chat_msg_time, "chat_msg_date" => $chat_msg_date, "chat_msg_text" => $chat_msg_text, "unread_messages_count" => $unread_messages_count, ]);
exit();
}
usleep(10000);
if ((time() - $time) > 60) {
echo json_encode(["command" => "timeout"]);
exit();
}
}
UPDATE 2: My hosting provider sent some information about it, but I can not understand what is it...:
sendto(3, "\306\0\0\0\3SELECT * FROM messages LEFT JOIN users ON users.username=messages.chat_msg_user_id WHERE chat_msg_client_id='222' AND chat_msg_id>'571' AND chat_notification='0' ORDER BY chat_msg_time DESC LIMIT 1", 202, MSG_DONTWAIT, NULL, 0) = 202
UPDATE 3: I forgot to say — I have 2 long poll connections per user. One for fetching new chats and new messages (for notifications) and another one for fetching messages while chatting.
PHP usually uses a threadpool to process requests. Putting execution to sleep is not really supported by this approach. You end up exhausting the available threads pretty quickly, and new requests won't get processed because all threads are sleeping.
You either need to increase the number of threads (which won't scale and may not be supported by your hosting provider), or switch to a different approach (by using a language/framework that supports asynchronous request processing, e.g. NodeJS).
See also this excerpt from an answer regarding long polling in PHP:
Note: With a real site, running this on a regular web-server like Apache will quickly tie up all the "worker threads" and leave it unable to respond to other requests.. There are ways around this, but it is recommended to write a "long-poll server" in something like Python's twisted, which does not rely on one thread per request. cometD is an popular one (which is available in several languages), and Tornado is a new framework made specifically for such tasks (it was built for FriendFeed's long-polling code)... but as a simple example, Apache is more than adequate! This script could easily be written in any language (I chose Apache/PHP as they are very common, and I happened to be running them locally)
Update:
My hosting provider said that Apache has too many connections to database and my server dieing cause of it
If this is the problem, then it might be fixable (until the other issue regarding PHP threads takes over) by closing the database connections before entering sleep, see this for PDO.
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