webman 框架
event_loop 使用了swoole
無(wú)法平滑重啟或者平滑關(guān)閉
php start.php stop -g
Workerman[start.php] stop
Workerman[start.php] is gracefully stopping ...
config/server:
'event_loop' => \Workerman\Events\Swoole::class,
app/bootstrap:
Swoole\Coroutine::set(['hook_flags' => SWOOLE_HOOK_ALL]);
在控制器中使用了協(xié)程代碼后,使用平滑重啟或者關(guān)閉-g參數(shù),命令行就會(huì)一直等待,請(qǐng)求也進(jìn)不來(lái)
代碼:
go(function(){
sleep(20);
echo "xxx";
});
ubuntu 22
php 8.3.13
Webman-framework v1.5.2
本地測(cè)試了下,沒(méi)發(fā)現(xiàn)問(wèn)題
workerman/webman-framework 1.5.24
workerman/workerman 4.1.16
感謝大佬回答,可能是我描述的還不夠清除。我又重新安裝了一遍,確實(shí)存在無(wú)法平滑關(guān)閉/重啟問(wèn)題。
步驟如下:
1.使用 composer 安裝 webman
2.修改 config/server.php 中的event_loop為 \Workerman\Events\Swoole::class
3.新建 app/bootstrap/SwooleConfig.php
4.在 SwooleConfig.php 文件中加入 Swoole\Coroutine::set(['hook_flags' => SWOOLE_HOOK_ALL]); 開啟協(xié)程
5.在 IndexController.php
加入?yún)f(xié)程代碼
go(function () {
sleep(5);
echo 123;
});
使用一個(gè)終端執(zhí)行 php start.php start
使用瀏覽器訪問(wèn)index,看到控制臺(tái)正確異步輸出 “123”
使用一個(gè)新的終端執(zhí)行 php start.php stop -g 關(guān)閉平滑關(guān)閉
php start.php stop -g
Workerman[start.php] stop
Workerman[start.php] is gracefully stopping ...
無(wú)響應(yīng),持續(xù)等待
如果不用瀏覽器訪問(wèn)index,沒(méi)有執(zhí)行過(guò)異步代碼,是可以正常平滑關(guān)閉的,一旦訪問(wèn)了協(xié)程代碼,就無(wú)法平滑關(guān)閉。
使用新終端執(zhí)行 php start.php stop 不加入 -g 參數(shù),如果協(xié)程暫未運(yùn)行結(jié)束,j舊的啟動(dòng)終端就會(huì)提示:
[FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!
[Coroutine-9]
#0 /app_project/webman/app/controller/IndexController.php(12): sleep()
#1 [internal function]: app\controller\IndexController->app\controller\{closure}()
11.使用新終端執(zhí)行 php start.php stop 不加入 -g 參數(shù),如果協(xié)程結(jié)束了,則是正常關(guān)閉
抱歉大佬,刪了又改幾次回復(fù),就是想排版清楚一些,方便大佬查看
補(bǔ)充在第4到第5步中還有一步:
在config/bootstrap.php,新增初始化類
return [
support\bootstrap\Session::class,
support\bootstrap\LaravelDb::class,
app\bootstrap\SwooleConfig::class, //新增
];
初步測(cè)試判斷是swoole的bug,swoole文檔說(shuō)調(diào)用 Swoole\Event::del() 后事件回調(diào)函數(shù)會(huì)釋放,但是實(shí)際沒(méi)有釋放,導(dǎo)致連接對(duì)象一直沒(méi)釋放。
workerman后面會(huì)發(fā)版本會(huì)兼容這個(gè)問(wèn)題。
好的,感謝大佬回答!
因?yàn)槲业?webman 項(xiàng)目已經(jīng)在運(yùn)行了,后續(xù)可以使用此命令跟新嗎?
composer update workerman/webman-framework
感謝大佬,剛剛測(cè)試了,發(fā)現(xiàn)2個(gè)疑問(wèn):
go(function(){
sleep(10);
echo "xxx"; //使用了stop -g 會(huì)立刻輸出,并未按上面的sleep 10秒后執(zhí)行
});
go(function(){
sleep(10);
echo "xxx";
$filePath = runtime_path() . DIRECTORY_SEPARATOR . date("Ymd") . "debug.log";
$folderPath = dirname($filePath);
if (!is_dir($folderPath)) {
mkdir($folderPath, 0755, true);
}
file_put_contents($filePath,"test", FILE_APPEND);
});
報(bào)錯(cuò)內(nèi)容:
使用了stop -g 會(huì)立刻輸出,并未的sleep 10秒后執(zhí)行,并且業(yè)務(wù)代碼出錯(cuò)
xxx
[FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!
[Coroutine-8]
--------------------------------------------------------------------
#0 /app_project/ffbox2/app/service/UserService.php(26): is_dir()
#1 [internal function]: app\service\UserService->app\service\{closure}()
sleep()會(huì)被信號(hào)打斷,會(huì)立刻返回。
stop -g原理是判斷連接數(shù)是否為0,為0則認(rèn)為可以安全關(guān)閉,并不會(huì)判斷是否有swoole協(xié)程在運(yùn)行。
deadlock 這個(gè)目前不好解決,你可以在 vendor/workerman/workerman/Events/Swoole.php 的 destroy() 方法
加一句slee(1);給協(xié)程退出一點(diǎn)時(shí)間試下
sleep(1);
Event::exit();
非常感謝大佬,加入了sleep(1),測(cè)試十分有效,我添加了一千個(gè)協(xié)程,都可以安全退出和重啟;
大佬這個(gè)小改動(dòng)會(huì)更新到compose中嗎?