Есть websocket сервер на Ratchet. Работает отлично сутками, памяти не жрет, не падает - как часы работает, но есть недостаток. Так как в коде используются блокирующие функции, то очередь React блокируется и пока старое сообщение не будет отработано новые запросы от websocket клиентом не будут обработаны сервером.
Что-бы этого избежать я сначала скомпилил php с поддержкой pthread, но, как оказалось потом запуск трида тоже блокирует очередь.
Такой код блокирует очередь React
class Message extends \Thread{
public function run(){
db_init();
app_init();
//тут код, отрабатывающий сообщения от WS
sleep(1000) //для простоты
}
}
...
public function onMessage(){
$work = new Message();
$work->start();
}
...
Я был уверенным, что после $work->start() будет создан новый поток, с новым конектом БД и своим новым окружением. Впрочем так оно и есть, НО... очередь блокируется, пока не завершится поток(да, можно создать хоть 100 параллельных потоков, они будут работать, а очередь будет заблокирована). Почему так не понимаю, поток вроде как для того и создан, чтобы параллельно выполняться, но какого то хера он блокирует родительский скрипт. Нагуглил у многих эта проблема с Ratchet. Ну да ладно, перехожу на fork, proc_open
Сейчас думаю что использовать: fork или proc_open. С форками никогда не работал, хочу поинтересоваться как лучше сделать через fork или proc_open?
Сервер простой
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\Http\HttpServer;
require "vendor/autoload.php";
class Websocket implements MessageComponentInterface {
public function onOpen(ConnectionInterface $conn) {
}
public function onMessage(ConnectionInterface $conn, $msg) {
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
pcntl_wait($status); //? что тут? return?
} else {
//тут код, обрабатывающий сообщение от WS...
//обращение к БД, чтение файлов, загрузка по http, все долгие операции
}
//ИЛИ
proc_open("php /message.php --mess={$msg}")
}
public function onClose(ConnectionInterface $conn) {
}
public function onError(ConnectionInterface $conn, \Exception $e) {
}
}
$myWs = new Websocket();
$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$server = new IoServer(new HttpServer(new WsServer($myWs)), $socket, $loop);
$socket->listen(7000, "127.0.0.1");
$loop->run();
Если форком, то что делать после отработки чилда? Если exit сделать, но весь скрипт падает, что делать в паренте? Или лучше proc_open?
Сообщения между процессами думаю делать на ZMQ... или просто через PIPE? Запускаемый процесс должен отработать сообщение и вернуть JSON основному скрипту, который разошлет ответ всем вебсокетам.
Простой пример того, чего хочу
Клиент(K), Сервер - WS
K: Соединение с WS
WS: OK
K: Mess Join(вход в чат)
WS: проверка сессии, пользователя, комнаты и прочие проверки долгие
K: Mess Chat(собственно, сообщение в чат)
WS: снова проверки выше, проверки доступа, подключение ботов, работа с http