比如一個定時任務(wù)在執(zhí)行中有兩步操作,Workerman 在使用 stop 停止時可能會出現(xiàn)前一個操作完成后一個操作未完成就停止的情況,雖然 Workerman 提供了 -g 參數(shù)來等待鏈接全部關(guān)閉后停止,但是這兩個操作可能沒有鏈接,也可能是長鏈接不會主動關(guān)閉。
有沒有一種機(jī)制,讓用戶自己控制這個關(guān)閉流程,比如向 Workerman 中注冊一個 StopHandler,當(dāng) Workerman 使用 stop 時,觸發(fā)這些 StopHandler,然后每個 Handler 以回調(diào)的形式告訴 Workerman 自己是否已經(jīng)可以結(jié)束了,當(dāng)所有 StopHandler 都告訴 Workerman 完成時,才真正結(jié)束。
現(xiàn)在有些長時間執(zhí)行的任務(wù),從零點幾秒到幾十秒不等,中間去讀數(shù)據(jù)庫,也會操作本地文件,也可能還有生成圖片,還有可能去連接遠(yuǎn)程的 http 接口,很容易出現(xiàn)這種情況下停止 Workerman 導(dǎo)致任務(wù)和數(shù)據(jù)處理了一半的情況。。
@walkor
-g 并不能完全解決,-g 只是等待連接關(guān)閉然后停止進(jìn)程,但是業(yè)務(wù)可能建立了不會關(guān)閉的長連接,比如與 Channel 之間的連接,也有可能有一個循環(huán)執(zhí)行的定時器,這個定時器要安全停止必須要做一些相關(guān)的工作,也有可能正在作一些其它的工作,這個工作是與連接無關(guān)的。
我看到國外的框架有個很好的思路,這里可以參考一下,比如我可以主動安裝一個信號監(jiān)聽器,當(dāng)發(fā)起停止命令時(也可以針對 -g 的停止,但 -g 的問題就是它要等待連接關(guān)閉,對有長鏈接時一直無法停止),就會觸發(fā)這個監(jiān)聽器,這個監(jiān)聽器需要主動解除自己的監(jiān)聽,當(dāng)所有的監(jiān)聽器都解除后,程序才退出。
示例如下:
Worker::onSignal(SIGHUP, function($watcherId) {
echo "收到 SIGHUP 安全停止信號,正在處理中..\n";
MyTasks::stopWorking();
//做一些收尾工作
//停止接收新的任務(wù)
//等待正在進(jìn)行的任務(wù)的結(jié)束
MyTasks::onCurrentTaskFinished(function() use ($watcherId) {
echo "MyTasks 已安全結(jié)束。\n";
Worker::cancel($watcherId);
});
});
這樣的話,用戶可以控制自己的業(yè)務(wù)安全退出。
重點是些工作并不是關(guān)閉連接那么簡單,而且有些清理工作是異步的。而 onWorkerStop 并不會等我去清理,它同步執(zhí)行完了就關(guān)閉了。
這個 -g 只是等待連接關(guān)閉我覺得其實沒有什么用處,只能用在簡單的短連接場景,比如我使用異步的 Redis 建立了連接,我和 Channel 建立了連接,這些連接本身是處于一層層的封裝之下,并不適合把他們都收集來關(guān)閉,再比如我可能有一個定時器,每秒鐘執(zhí)行,這個定時器要安全關(guān)閉必須要等里面的東西完全執(zhí)行完,而這個定時器內(nèi)部的東西又有可能是異步的動作,這些異步操作也可能不是網(wǎng)絡(luò)請求啊,也可能我裝了個擴(kuò)展是異步寫文件呢。
這時去主動關(guān)閉這些連接顯然很復(fù)雜,需要更有效的辦法,我覺得自定義信號監(jiān)聽器就是個不錯的辦法。
每添加一個監(jiān)聽器,就有一個 countDown 計數(shù)增加,當(dāng)它們收到信息號主動 cancel($watcherId) 的時候,這個 countDown 就減少,當(dāng)減少到 0 的時候就退出,這樣用戶可以自己手動控制安全關(guān)閉的過程。
算了,有空我來提個 Pull Request 吧。。