如何优雅的停止正在处理队列消息的 worker 呢?

2021-06-12 21:52:08 +08:00
 tedd
一个发送消息的源头服务器,一个队列,两个 worker 。worker 从队列中拿消息进行处理,处理过程中可能会因为数据源出现了更新,因此 worker 需要停止当前的处理并退出。请问有什么设计模式可以应用的吗?技术栈是 Redis (queue)、worker 是 Node 写的。

我目前想到的一个很笨的方法是还是用将正在处理的任务状态存在 Redis 中,当 worker 开始的时候,将这个 taskId:state 键值对的 state 值改成 processing,如果发送消息的源头出现了数据更新,则源头服务器更新 Redis 中的任务状态为 cancel,worker 处理数据其实是个大 loop,所以每次 loop 的时候先检查任务的 state,如果发现是 cancel 了,那就退出 loop 即退出处理。

又或者用 Redis 的 pubsub ?源头服务推送 cancel 的消息,worker 作为 sub 监听,如果碰到 cancel 的通知,就 process.exit?
2156 次点击
所在节点    程序员
6 条回复
ericls
2021-06-12 23:41:28 +08:00
如果要退出,也需要有一个 rollback 的机制,不然处理到一半的数据怎么办?如果有了 rollback 机制,就用新的任务去 rollback 旧的任务就可以了。
tedd
2021-06-13 06:10:55 +08:00
@ericls 不需要 rollback,因为数据写入是在最后进行的(而且写入的数据量很小耗时可忽略不计),没有处理完,已处理的数据可以丢弃不管。
ericls
2021-06-13 06:15:01 +08:00
@tedd 考虑网络延迟的话,很难保证 queue 这边发出新的信号的时候,以前拿到的任务还没处理完。除非你用个锁之类的东西,就是等到多久没有等到取消的情况下再做最后的写入?

但是这也需要你有一个明确的条件,只要达到这个条件,就 100%放心写入,否则有可能被取消。
不然的话,感觉就是个 debounce 的问题?
Muninn
2021-06-13 10:31:48 +08:00
除非有信心取了一定处理,或者取了丢弃了也无所谓,才建议使用 redis 当队列。

你随便用个专业的队列有 ACK 机制都不用在意这个问题的。

想用 Redis 实现 ACK 还是挺麻烦的。用它新出的 Steam 模型吧,ACK 是有了但又带来其他的复杂度。
rockyliang
2021-06-13 13:12:01 +08:00
你可以弄两个队列,比如 v1 版本的源数据放入到 v1 队列,A worker 负责处理。如果源数据有更新,则把新版本的数据放入到 v2 队列,然后再另起一个 B worker 处理 v2 版本的队列。等 v1 的队列都处理完了,就 Kill 掉 A worker
retanoj
2021-06-15 09:00:47 +08:00
感觉你的思路像是做一个 worker 开关
我支持:)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/783126

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX