Отправленные сервером события Опрос, вызывающий длительные задержки

У меня есть разъем, который вызовет RESP API, используя cURL и PHP.

Мне нужно вызывать один метод каждую секунду, чтобы проверять новые сообщения, а затем обрабатывать их. Я использовал следующие два подхода для обработки сообщений

  1. Опрос AJAX с использованием SetInterval() : вызывать скрипт php один раз в секунду. Это отлично работает, за исключением того, что я не могу одновременно запустить несколько SetInterval() из разных вкладок браузера. (Я не хочу, чтобы пользователь открыл 10 вкладков браузера, что приводит к тому, что один пользователь, имеющий 10 SetInterval() , работает одновременно.
  2. События, отправленные сервером с использованием EventSource : сервер отправит обновление браузера после появления новых данных в очереди. Это замедляет время ответа. Каждый вызов, который я делаю для скрипта, занимает около 20 + секунд, чтобы завершить, что является проблемой. Я не знаю, почему это происходит.

Вот моя реализация SetInterval()

 function startCalls(){ //update the screen using Intervals refreshIntervalId = setInterval(function() { $.getJSON("index.php", {'method': 'getMessages', 'jSON': true} , function(data){ processServerData(data); }); }, 1000); } 

как только пользователь входит в систему, я startCalls() эту функцию startCalls()

внутри файла index.php У меня есть этот код для вызова

 if($method == 'getMessages'){ $messaging = new ICWS\Messaging($icws); $messaging->processMessages(); $myQueue = $messaging->getCallsQueue(); echo json_encode($myQueue ); } 

Вот моя вторая реализация «Server-Sent Events»

 //Server Side Message Polling function startPolling(evtSource){ evtSource.addEventListener("getMessagingQueue", function(e) { var data = JSON.parse(e.data); processServerData(data) }, false); } 

как только пользователь входит в систему, я startPolling( new EventSource("poll.php") ); эту функцию startPolling( new EventSource("poll.php") );

Для простоты предположим, что мой метод processServerData выглядит так

 function processServerData(data){ console.log('process the data received from the server'); } 

вот мой php-код

 <?php require 'autoloader.php'; //Make sure cURL is enabled on the server if(!is_callable('curl_init')){ exit('cURL is disabled on this server. Before making API calls cURL extension must be enabled.'); } if( isset($_COOKIE['icws_username']) ){ $user = trim($_COOKIE['icws_username']); } if( isset($_COOKIE['icws_password']) ){ $pass = trim($_COOKIE['icws_password']); } if( isset($_COOKIE['icws_station']) ){ $stationName = trim($_COOKIE['icws_station']); } if( !isset($user, $pass, $stationName) ){ echo json_encode(array('status' => 'The IC credentials you entered are invalid')); exit; } $scheme = 'http'; $host = 'host'; $port = '8018'; $sleepTime = 1; $url = sprintf('%s://%s:%s@%s:%s', $scheme, $user, $pass, $host, $port); try { header("Content-Type: text/event-stream\n\n"); session_start(); //configure the connection $conf = new ICWS\Config\Config($url, $stationName); //create a new instance of icws $attrebutes = array(); $icws = new ICWS\Connection($conf, $attrebutes, true); $messaging = new ICWS\Messaging($icws); ob_end_clean(); while(true){ header("Content-Type: text/event-stream" . PHP_EOL); header("Cache-Control: no-cache" . PHP_EOL); $messaging->processMessages(); $result = $messaging->getCallsQueue(); //$current = $icws->getCurrentUserStatusQueue(); echo 'event: getMessagingQueue' . PHP_EOL; echo 'data: ' . json_encode( $result) . PHP_EOL; echo PHP_EOL; //required ob_end_flush(); flush(); sleep(1); } } catch(Exception $e){ echo $e->getMessage(); } ?> в <?php require 'autoloader.php'; //Make sure cURL is enabled on the server if(!is_callable('curl_init')){ exit('cURL is disabled on this server. Before making API calls cURL extension must be enabled.'); } if( isset($_COOKIE['icws_username']) ){ $user = trim($_COOKIE['icws_username']); } if( isset($_COOKIE['icws_password']) ){ $pass = trim($_COOKIE['icws_password']); } if( isset($_COOKIE['icws_station']) ){ $stationName = trim($_COOKIE['icws_station']); } if( !isset($user, $pass, $stationName) ){ echo json_encode(array('status' => 'The IC credentials you entered are invalid')); exit; } $scheme = 'http'; $host = 'host'; $port = '8018'; $sleepTime = 1; $url = sprintf('%s://%s:%s@%s:%s', $scheme, $user, $pass, $host, $port); try { header("Content-Type: text/event-stream\n\n"); session_start(); //configure the connection $conf = new ICWS\Config\Config($url, $stationName); //create a new instance of icws $attrebutes = array(); $icws = new ICWS\Connection($conf, $attrebutes, true); $messaging = new ICWS\Messaging($icws); ob_end_clean(); while(true){ header("Content-Type: text/event-stream" . PHP_EOL); header("Cache-Control: no-cache" . PHP_EOL); $messaging->processMessages(); $result = $messaging->getCallsQueue(); //$current = $icws->getCurrentUserStatusQueue(); echo 'event: getMessagingQueue' . PHP_EOL; echo 'data: ' . json_encode( $result) . PHP_EOL; echo PHP_EOL; //required ob_end_flush(); flush(); sleep(1); } } catch(Exception $e){ echo $e->getMessage(); } ?> 

Кажется, что сервер блокирует все запросы, которые попадают на сервер, до тех пор, пока бесконечный цикл не остановится с помощью «обновления страницы», как только я обновляю страницу, остальные запросы обрабатываются немедленно

Почему событие Server-Sent вызвало такую ​​проблему?

В этом вопросе можно найти большой ресурс для разных типов полинга

Все выглядит уверенно, поэтому я собираюсь предположить, что вас атакует блокировка сеанса. Сеансы PHP блокируют файл сеанса, так что только один скрипт PHP может использовать сеанс за раз; когда вы думаете об этом, это отличная идея!

Проблема с сеансами и SSE заключается в том, что процесс SSE PHP работает навсегда, и поэтому он блокирует сеанс навсегда. Если какой-либо другой PHP-скрипт пытается работать с одним и тем же сеансом, он будет блокировать (на вызове session_start() , я считаю).

Это похоже на хорошую статью по этому вопросу; совет – вызвать session_write_close() только вам станет нужно больше сеанса. Например, если вам просто нужно использовать сеанс, чтобы проверить, что они ранее разрешили себя, то сразу после этого вы вызываете session_write_close() , а другие процессы не будут заблокированы.