Workerman 能提供类似 StopHandler 的功能来让用户控制安全停止吗?

pader

比如一个定时任务在执行中有两步操作,Workerman 在使用 stop 停止时可能会出现前一个操作完成后一个操作未完成就停止的情况,虽然 Workerman 提供了 -g 参数来等待链接全部关闭后停止,但是这两个操作可能没有链接,也可能是长链接不会主动关闭。

有没有一种机制,让用户自己控制这个关闭流程,比如向 Workerman 中注册一个 StopHandler,当 Workerman 使用 stop 时,触发这些 StopHandler,然后每个 Handler 以回调的形式告诉 Workerman 自己是否已经可以结束了,当所有 StopHandler 都告诉 Workerman 完成时,才真正结束。

现在有些长时间执行的任务,从零点几秒到几十秒不等,中间去读数据库,也会操作本地文件,也可能还有生成图片,还有可能去连接远程的 http 接口,很容易出现这种情况下停止 Workerman 导致任务和数据处理了一半的情况。。

1650 5 0
5个回答

walkor

如果stop不用-g,workerman主进程给子进程发出stop信号后,如果对应子进程2秒没没有正常退出,主进程会发送kill信号强行杀死对应进程,这种情况可能会导致业务处理一半的情况。

如果stop使用-g则不会强行杀死子进程,就不会有这个问题了。

我觉得你说的这个问题用-g就能解决。

  • 暂无评论
pader

@walkor

-g 并不能完全解决,-g 只是等待连接关闭然后停止进程,但是业务可能建立了不会关闭的长连接,比如与 Channel 之间的连接,也有可能有一个循环执行的定时器,这个定时器要安全停止必须要做一些相关的工作,也有可能正在作一些其它的工作,这个工作是与连接无关的。

我看到国外的框架有个很好的思路,这里可以参考一下,比如我可以主动安装一个信号监听器,当发起停止命令时(也可以针对 -g 的停止,但 -g 的问题就是它要等待连接关闭,对有长链接时一直无法停止),就会触发这个监听器,这个监听器需要主动解除自己的监听,当所有的监听器都解除后,程序才退出。

示例如下:

Worker::onSignal(SIGHUP, function($watcherId) {
    echo "收到 SIGHUP 安全停止信号,正在处理中..\n";

    MyTasks::stopWorking();

    //做一些收尾工作
    //停止接收新的任务
    //等待正在进行的任务的结束

    MyTasks::onCurrentTaskFinished(function() use ($watcherId) {
        echo "MyTasks 已安全结束。\n";
        Worker::cancel($watcherId);
    });
});

这样的话,用户可以控制自己的业务安全退出。

  • 暂无评论
walkor

workerman 提供了 onWorkerStop 回调,MyTasks::stopWorking(); 可以在这里运行,在这里你可以关闭所有连接,等所有连接关闭了就自动退出了。

  • 暂无评论
pader

重点是些工作并不是关闭连接那么简单,而且有些清理工作是异步的。而 onWorkerStop 并不会等我去清理,它同步执行完了就关闭了。

  • 暂无评论
pader

这个 -g 只是等待连接关闭我觉得其实没有什么用处,只能用在简单的短连接场景,比如我使用异步的 Redis 建立了连接,我和 Channel 建立了连接,这些连接本身是处于一层层的封装之下,并不适合把他们都收集来关闭,再比如我可能有一个定时器,每秒钟执行,这个定时器要安全关闭必须要等里面的东西完全执行完,而这个定时器内部的东西又有可能是异步的动作,这些异步操作也可能不是网络请求啊,也可能我装了个扩展是异步写文件呢。

这时去主动关闭这些连接显然很复杂,需要更有效的办法,我觉得自定义信号监听器就是个不错的办法。

每添加一个监听器,就有一个 countDown 计数增加,当它们收到信息号主动 cancel($watcherId) 的时候,这个 countDown 就减少,当减少到 0 的时候就退出,这样用户可以自己手动控制安全关闭的过程。

算了,有空我来提个 Pull Request 吧。。

  • 暂无评论
年代过于久远,无法发表回答
🔝