各位大大,新年快樂!
最近在開發(fā)一個(gè)websocket服務(wù),需要根據(jù)websocket連接上來時(shí)攜帶的參數(shù)來創(chuàng)建一個(gè)個(gè)的session,分別輪詢外部的接口服務(wù)器,來獲取實(shí)時(shí)的話務(wù)系統(tǒng)狀態(tài)與話務(wù)事件。于是我考慮在GatewayWorker 的onWebSocketConnect回調(diào)函數(shù)中使用while(true)循環(huán)來不斷的輪詢接口,直到這個(gè)session連接斷開。
HTTP的請求基于GuzzleHttp開發(fā),在實(shí)際運(yùn)行中,輪詢個(gè)5到6次后會(huì)報(bào)process_timeout的錯(cuò)誤,堆棧信息如下:
< HTTP/1.1 200
< Transfer-Encoding: chunked
< Date: Sun, 30 Jan 2022 01:41:50 GMT
<
* Connection #0 to host 192.168.15.4 left intact
* Hostname 192.168.15.4 was found in DNS cache
* Trying 192.168.15.4...
* TCP_NODELAY set
* Connected to 192.168.15.4 (192.168.15.4) port 8080 (#0)
> POST /AeonixProxy/proxy HTTP/1.1
Host: 192.168.15.4:8080
User-Agent: GuzzleHttp/7
SOAPAction: getEventsRequest
Content-Type: text/xml; charset=UTF-8
Content-Type: text/xml; charset=UTF-8
Content-Length: 294
* upload completely sent off: 294 out of 294 bytes
process_timeout:
#1 /home/vagrant/code/AeonixWebsocketService/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php(183): GuzzleHttp\Handler\CurlMultiHandler->tick()
#2 /home/vagrant/code/AeonixWebsocketService/vendor/guzzlehttp/promises/src/Promise.php(248): GuzzleHttp\Handler\CurlMultiHandler->execute()
#3 /home/vagrant/code/AeonixWebsocketService/vendor/guzzlehttp/promises/src/Promise.php(224): GuzzleHttp\Promise\Promise->invokeWaitFn()
#4 /home/vagrant/code/AeonixWebsocketService/vendor/guzzlehttp/promises/src/Promise.php(269): GuzzleHttp\Promise\Promise->waitIfPending()
#5 /home/vagrant/code/AeonixWebsocketService/vendor/guzzlehttp/promises/src/Promise.php(226): GuzzleHttp\Promise\Promise->invokeWaitList()
#6 /home/vagrant/code/AeonixWebsocketService/vendor/guzzlehttp/promises/src/Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending()
#7 /home/vagrant/code/AeonixWebsocketService/app/Aeonix/Telephony.php(311): GuzzleHttp\Promise\Promise->wait()#8 /home/vagrant/code/AeonixWebsocketService/app/GatewayWorker/Events.php(149): App\Aeonix\Telephony->sendToProxyEndpoint()
#9 [internal function]: App\GatewayWorker\Events::onWebSocketConnect()
#10 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/gateway-worker/src/BusinessWorker.php(419): call_user_func()
#11 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/workerman/Connection/TcpConnection.php(656): GatewayWorker\BusinessWorker->onGatewayMessage()
#12 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/workerman/Events/Select.php(292): Workerman\Connection\TcpConnection->baseRead()
#13 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/workerman/Worker.php(2408): Workerman\Events\Select->loop()
#14 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/gateway-worker/src/BusinessWorker.php(197): Workerman\Worker->run()
#15 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/workerman/Worker.php(1541): GatewayWorker\BusinessWorker->run()
#16 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/workerman/Worker.php(1371): Workerman\Worker::forkOneWorkerForLinux()
#17 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/workerman/Worker.php(1345): Workerman\Worker::forkWorkersForLinux()
#18 /home/vagrant/code/AeonixWebsocketService/vendor/workerman/workerman/Worker.php(546): Workerman\Worker::forkWorkers()
#19 /home/vagrant/code/AeonixWebsocketService/app/Console/Commands/GatewayWorkerServer.php(63): Workerman\Worker::runAll()
#20 /home/vagrant/code/AeonixWebsocketService/app/Console/Commands/GatewayWorkerServer.php(55): App\Console\Commands\GatewayWorkerServer->start()
#21 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): App\Console\Commands\GatewayWorkerServer->handle()
#22 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Container/Util.php(40): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#23 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\Container\Util::unwrapIfClosure()
#24 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\Container\BoundMethod::callBoundMethod()
#25 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Container/Container.php(653): Illuminate\Container\BoundMethod::call()
#26 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Console/Command.php(136): Illuminate\Container\Container->call()
#27 /home/vagrant/code/AeonixWebsocketService/vendor/symfony/console/Command/Command.php(298): Illuminate\Console\Command->execute()
#28 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Console/Command.php(121): Symfony\Component\Console\Command\Command->run()
#29 /home/vagrant/code/AeonixWebsocketService/vendor/symfony/console/Application.php(1005): Illuminate\Console\Command->run()
#30 /home/vagrant/code/AeonixWebsocketService/vendor/symfony/console/Application.php(299): Symfony\Component\Console\Application->doRunCommand()
#31 /home/vagrant/code/AeonixWebsocketService/vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun()
#32 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Console/Application.php(94): Symfony\Component\Console\Application->run()
#33 /home/vagrant/code/AeonixWebsocketService/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(129): Illuminate\Console\Application->run()
#34 /home/vagrant/code/AeonixWebsocketService/artisan(37): Illuminate\Foundation\Console\Kernel->handle()
#35 {main}
* stopped the pause stream!
* Closing connection 0
請問各位大佬,能不能這樣做?處理這種輪詢請求的最佳方式是什么?
謝謝大家!
你這樣死循環(huán),系統(tǒng)根本不會(huì)把控制權(quán)還給workerman,所以woekerma后續(xù)也無法處理任何東西,所以肯定是不行的.但是我不了解你想實(shí)現(xiàn)的場景.你單純說要不停輪詢,這我沒法給你建議
謝謝您的回復(fù)。具體的場景是這樣的,要輪詢的服務(wù)器是一臺電話軟交換服務(wù)器,對外只提供了HTTP接口,需要輪詢獲取系統(tǒng)中最新的話機(jī)及話務(wù)狀態(tài),有一個(gè)getEvents請求到服務(wù)器后會(huì)有10秒鐘的阻塞,如果10秒鐘內(nèi)服務(wù)器有新的話務(wù)事件或狀態(tài),此次請求會(huì)立即返回新的話務(wù)事件或狀態(tài),如果10秒鐘內(nèi)沒有事件或狀態(tài),則返回一個(gè)通用的響應(yīng)。無論有沒有新的事件或狀態(tài),在上一個(gè)getEvents請求得到響應(yīng)后,要立刻發(fā)起新的getEvents請求,如此循環(huán)下去,直到一個(gè)連接session的斷開。
我也考慮過在onWorkerStart中使用定時(shí)器來定時(shí)發(fā)起getEvents請求,把新的連接session放入一個(gè)數(shù)組來遍歷,但無法做到得到響應(yīng)后再發(fā)送getEvents請求,導(dǎo)致產(chǎn)生了過多的請求。
雖然你的需求我看的有點(diǎn)懵,但是你的處理方式是肯定不行的,按你這思路,一個(gè)人請求上來后,就一直卡在這輪詢了,這個(gè)進(jìn)程根本不可能再接收其它用戶連接了.
我先說好,我不確定理解了你得邏輯,但是我肯定,不需要這樣死循環(huán)肯定能處理得,只是你思維陷進(jìn)誤區(qū)了
// 我這只是寫個(gè)簡單思路,這里面肯定要攜帶你發(fā)起 新getEvents得參數(shù),還有,里面也要做一個(gè)退出得條件
public function handle($client_id,$time){
// 沒有什么說是一秒不能停得,這種我只能說是你架構(gòu)有問題
Timer::add(1,function ()use($client_id,$time){
$http = new Workerman\Http\Client();
$http->get('https://example.com/', function($response) use($client_id,$time) {
var_dump($response->getStatusCode());
echo $response->getBody();
$status = '';
$now_time = time();
// 有新狀態(tài)
if ($status){
// 發(fā)送響應(yīng),
Gateway::sendToClient( $client_id, '');
// 創(chuàng)建新鏈接
$time = $now_time;
}else{
if ($now_time - $time > 10){
//10秒鐘內(nèi)沒有事件或狀態(tài),返回一個(gè)通用的響應(yīng)
//發(fā)起新請求
$time = $now_time;
}else{
// 沒達(dá)到10秒,繼續(xù)輪詢
}
}
$this->handle($client_id,$time);
}, function($exception)use($client_id,$time){
echo $exception;
$now_time = time();
if ($now_time - $time > 10){
//10秒鐘內(nèi)沒有事件或狀態(tài),返回一個(gè)通用的響應(yīng)
//發(fā)起新請求
$time = $now_time;
}else{
// 沒達(dá)到10秒,繼續(xù)輪詢
}
$this->handle($client_id,$time);
});
},[],false);
}
public function onWebSocketConnect(string $client_id, array $data){
$this->handle($client_id,time());
}
感謝回復(fù)!按照您的指點(diǎn),我把GuzzleHttp換成了Workerman的http-client來請求服務(wù)器接口,然后把接口輪詢的邏輯做在了success和error回調(diào)中,貌似不會(huì)報(bào)錯(cuò)了,我再持續(xù)觀察下,謝謝!