V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tedd
V2EX  ›  程序员

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

  •  
  •   tedd · 341 天前 · 1633 次点击
    这是一个创建于 341 天前的主题,其中的信息可能已经有所发展或是发生改变。
    一个发送消息的源头服务器,一个队列,两个 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?
    6 条回复    2021-06-15 09:00:47 +08:00
    ericls
        1
    ericls  
       341 天前   ❤️ 1
    如果要退出,也需要有一个 rollback 的机制,不然处理到一半的数据怎么办?如果有了 rollback 机制,就用新的任务去 rollback 旧的任务就可以了。
    tedd
        2
    tedd  
    OP
       341 天前 via iPhone
    @ericls 不需要 rollback,因为数据写入是在最后进行的(而且写入的数据量很小耗时可忽略不计),没有处理完,已处理的数据可以丢弃不管。
    ericls
        3
    ericls  
       341 天前   ❤️ 1
    @tedd 考虑网络延迟的话,很难保证 queue 这边发出新的信号的时候,以前拿到的任务还没处理完。除非你用个锁之类的东西,就是等到多久没有等到取消的情况下再做最后的写入?

    但是这也需要你有一个明确的条件,只要达到这个条件,就 100%放心写入,否则有可能被取消。
    不然的话,感觉就是个 debounce 的问题?
    Muninn
        4
    Muninn  
       341 天前   ❤️ 1
    除非有信心取了一定处理,或者取了丢弃了也无所谓,才建议使用 redis 当队列。

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

    想用 Redis 实现 ACK 还是挺麻烦的。用它新出的 Steam 模型吧,ACK 是有了但又带来其他的复杂度。
    rockyliang
        5
    rockyliang  
       340 天前   ❤️ 1
    你可以弄两个队列,比如 v1 版本的源数据放入到 v1 队列,A worker 负责处理。如果源数据有更新,则把新版本的数据放入到 v2 队列,然后再另起一个 B worker 处理 v2 版本的队列。等 v1 的队列都处理完了,就 Kill 掉 A worker
    retanoj
        6
    retanoj  
       339 天前 via iPhone   ❤️ 1
    感觉你的思路像是做一个 worker 开关
    我支持:)
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4015 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 03:46 · PVG 11:46 · LAX 20:46 · JFK 23:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.