Slack机器人的零停机部署

8
我们使用BotKit开发机器人,现在我们试图解决最小化部署停机时间的问题。
服务器和Docker容器正在该服务器上运行。容器内运行连接到RTM服务器(Slack)的bot-app实例。 当我开始部署bot-app的新版本(v2)时,我希望获得零停机时间,用户不应看到“ bot离线”。
部署脚本运行第二个Docker容器,并使用bot-app的新版本。 bot-app也连接到RTM服务器。以这种方式,在两个应用程序同时运行,连接到RTM服务器并响应用户命令(用户将看到两个答案)之前有几秒钟。
如果我们既想获得零停机时间,又想防止用户同时与两个实例进行交互,我们可以采取以下最佳决策:
决策1:允许两个实例同时响应用户命令的可能性较小。
决策2:放弃零停机时间部署。在这种情况下,部署脚本首先停止第一个Docker容器,然后启动另一个Docker容器。此时,应用程序将无法响应用户命令,这些命令被发送在当前应用程序版本停止和新应用程序完全启动之间。
决策3:采用并行运行当前应用程序和新版本应用程序或互斥锁的交互。一般原理如下: 1)当前应用程序版本正在运行 2)部署脚本启动新的应用程序版本 3)当新的应用程序版本几乎运行并准备好连接到RTM服务器时,它向当前应用程序版本发送关闭RTM连接的命令。 4)当前应用程序版本关闭RTM连接 5)新的应用程序版本打开RTM连接
我认为还有其他不错的解决方案。
你的应用程序中,你会如何解决这个问题呢?
2个回答

1
抱歉,我又想到了另一个主意。
我之前描述的方法可能会对你现有的代码造成很大的干扰,因为你可能需要停止使用botkit(或者至少不使用它来进行RTM API通信)。一种较少干扰的方法是使用某种外部方式来表示已经处理过某个特定消息。
例如,使用Redis,当消息进来时,让机器人执行以下命令:
SET message:<message timestamp> 1 NX PX 30000
NX选项表示此命令仅在键不存在时才会成功。因此,第一个执行此操作的机器人实例将成功,而另一个实例将失败。只有当此命令成功时,机器人才应处理消息并做出响应。
(PX 30000设置了30秒的过期时间,以避免Redis被这些键填满。)
这应该使您通过重叠运行的机器人实例来进行零停机升级,而无需担心消息被处理两次。
请注意,在此方案中,如果机器人以非优雅的方式关闭,则仍然可能完全丢失消息。 (它可能会在调用SET命令后但在实际处理消息之前死亡。)具有两阶段“获取/删除”的真实队列会更好,但那样您就回到了我的其他答案。 :-)

谢谢smarx!这是一个非常好的解决方案!与第一种方案不同,它看起来更简单可靠。 - vovan

0

我考虑的一个想法是将其分成两个组件:

  1. 一个组件,保持与Slack RTM API连接的WebSocket。该组件仅从API读取消息并将其放入队列中。(我们称之为“排队者”)
  2. 实际的“机器人”,它从队列中读取消息并根据需要做出响应。

根据您的机器人行为方式,它可以直接使用Web API,或者可能将自己的消息放在出站队列上,由“排队者”通过RTM API发送。

这种架构可能解决了您的问题...现在您可以在升级时短暂地关闭机器人——响应只会延迟到新版本运行,或者您可以同时运行两个版本的机器人,并依靠队列的语义来防止两个版本响应同一条消息。


这可以防止机器人具有状态。如果没有直接的Websocket连接,您将不得不模拟对话对象。 - Robbie Guilfoyle
这是真的。(或者至少状态需要是外部于机器人进程的。) - user94559

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接