項(xiàng)目需要使用異步Http組件,在回調(diào)中向客戶端返回?cái)?shù)據(jù),問如何先掛起連接不斷開,然后手動發(fā)送數(shù)據(jù)
我也比較好奇這個(gè)問題怎樣處理才是最合適的,我們之前系統(tǒng)的處理思路是,第一個(gè)請求過來先把請求參數(shù)入到隊(duì)列,然后給客戶端返回一個(gè)隊(duì)列id(自定義生成,跟隊(duì)列任務(wù)進(jìn)行綁定),客戶端收到隊(duì)列id后定時(shí)來調(diào)用戶獲取隊(duì)列結(jié)果的接口來取隊(duì)列消費(fèi)結(jié)果。服務(wù)器這邊開啟redis-queue服務(wù)消費(fèi)隊(duì)列,消費(fèi)成功后將結(jié)果保存在以隊(duì)列id為key的緩存中。
目前建議使用webman自定義進(jìn)程去做掛連接。
后面workerman v5 配合fiber協(xié)程可以做到讓webman掛起當(dāng)前請求,代碼類似這樣。
app/functions.php
<?php
use Workerman\Worker;
function get($url) {
$http = new Workerman\Http\Client();
$event_loop = Worker::getEventLoop()->driver();
$suspension = $event_loop->getSuspension();
$http->get($url, function($response) use ($suspension){
return $suspension->resume((string)$response->getBody());
});
return $suspension->suspend();
}
app/controller/Index.php
<?php
namespace app\controller;
use support\Request;
class Index
{
public function index(Request $request)
{
return get('http://example.com');
}
}
需要 php >= 8.1, 安裝 composer require revolt/event-loop
,設(shè)置 config/server.php
為 'event_loop' => Workerman\Events\Revolt::class
。
workerman v5還沒有發(fā)布,workerman v5需要等待revolt/event-loop
發(fā)穩(wěn)定版本。
webman目前composer 依賴的仍然是 v4,無法直接安裝v5。
使用fiber協(xié)程的好處就是可以暫停代碼及恢復(fù)執(zhí)行,實(shí)現(xiàn)用同步的方式寫異步代碼。缺點(diǎn)是要做全局變量隔離,比如request()這些函數(shù)沒辦法在協(xié)程里使用了。
之后這么改是默認(rèn)還是一個(gè)進(jìn)程在同一時(shí)間接受1個(gè)http請求,在上面這種通過fiber讓出控制權(quán)的場景會變成同時(shí)保持多個(gè)http連接吧。