Обновление веб-канала без блокировки основного потока - PullRequest
0 голосов
/ 08 мая 2020

У меня есть торговый бот, который работает синхронно в l oop:

  1. curl для данных книги заказов,
  2. trade - отправить / отменить предложение
  3. continue

Этот подход работает нормально, но некоторые каналы книги заказов не обновляются, если вы запрашиваете их по обычному HTTPS. Эти стороны предлагают каналы Websocket. Теперь это добавляет сложности, потому что с одной стороны мне нужно обрабатывать сообщения Websocket. С другой стороны, я запускаю бота в l oop.

Я пробовал подход с событием l oop. Fetcher обновляется сообщениями веб-сокета, OfferManager торгуется по методу run:

<?php

$fetcher = new FetchOffersExchangeWebsocket();
$manager = new SellOnlyOfferManager($fetcher);

$loop = \React\EventLoop\Factory::create();
$reactConnector = new \React\Socket\Connector($loop);
$connector = new \Ratchet\Client\Connector($loop, $reactConnector);

$connector('wss://api.trading.net/websocket')
    ->then(function(Ratchet\Client\WebSocket $conn) use($fetcher, $manager) {
        $subscribe = [
            "action" => "subscribe",
            "path" => "orderbook"
        ];

        $conn->send(json_encode($subscribe));

        $conn->on('message', function(\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn, $fetcher, $manager) {
            $message = json_decode((string) $msg, true);

            $fetcher->update($message);
            $manager->run();

        });

    }, function(\Exception $e) use ($loop) {
        echo "Could not connect: {$e->getMessage()}\n";
        $loop->stop();
    });

$loop->run();

Первая очевидная проблема, которая возникла, заключается в том, что OfferManager->run() блокирует выполнение обновления веб-сокета. В этом случае, если есть много обновлений веб-сокетов, над которыми нужно действовать, мой бот отстает, поскольку он застрял на некоторых старых сообщениях, которые выполняют run(), и все это требует времени.

Я не уверен, как лучше всего подойти к этому , но мне кажется, что мне нужно обновить Websocket в одном потоке и у меня есть способ поделиться конечным состоянием (снимком книги заказов) с потоком, в котором работает бот l oop.

Is есть ли какой-нибудь generi c подход к этой проблеме?

Есть ли чистый способ нанять PHP для решения этой проблемы? Кажется, я мог бы запустить бота на переднем плане и запустить обновление Websocket асинхронно, используя: https://www.php.net/manual/en/intro.parallel.php, а затем используя Channel, я мог бы передать эти данные обратно на передний план.

Любые подсказки приветствуются.

РЕДАКТИРОВАТЬ: Я не уверен, как правильно подойти к этому, но помогло использование неблокирующего потока для получения данных Websocket. stream_set_blocking($stream, false). Если в потоке нет данных, он возвращает пустую строку, но не блокирует выполнение. Затем я могу запустить fread в потоке до тех пор, пока не будет данных, а затем я могу запустить свой: $manager->run(). После его завершения я догоняю все сообщения, ожидающие обработки в буфере. Это не блокирует выполнение l oop.

...