我们使用BotKit开发bot,现在我们尝试以最小的部署停机时间来解决问题。
此服务器上运行服务器和docker容器。内部容器运行bot-app实例与RTM-server(Slack)连接。 当我开始部署bot-app的新版本(v2)时,我希望零停机时间,用户不应该看到"僵尸程序离线"。
部署脚本使用新版本的bot-app运行第二个docker容器。 bot-app也连接到RTM服务器。通过这种方式,当两个应用程序都运行时,几秒钟就连接到RTM服务器并响应用户命令(用户将看到他的命令的两个答案)。
如果一方面我们希望获得零停机时间,另一方面,我们希望阻止用户同时与这两个实例进行交互,那么我可以得到什么最佳决策?
决定1: 当两个实例都响应用户命令时,允许碰撞的可能性很小。
决定2: 放弃零停机部署。在这种情况下,部署脚本首先停止第一个docker-container,然后启动另一个docker-container。该应用程序不会响应用户命令,在停止当前版本的应用程序和完全启动新版本的应用程序之间发送。
决定3: 随着并行运行当前和新版本的应用程序或互斥体的交互。一般示意图: 1)当前版本的应用程序正在运行 2)部署脚本启动新版本的应用程序 3)我在新版本的应用程序几乎运行并准备连接到RTM服务器时,它发送到当前版本的app命令以关闭RTM连接。 4)当前版本的应用程序关闭RTM连接 5)新版app打开RTM连接
我认为还有其他好的解决方案。
您如何在申请中解决此问题?
答案 0 :(得分:1)
(对不起第二个回复;有另一个想法。)
我之前描述的方法对您现有的代码非常具有破坏性,因为您可能需要停止使用botkit(或者至少不使用它来进行RTM API通信)。一种可能破坏性较小的方法是使用某种外部方式来表示已经处理了给定消息。
例如,使用Redis,让机器人在收到消息时执行以下命令:
SET message:<message timestamp> 1 NX PX 30000
NX
选项表示只有当密钥不存在时,此命令才会成功。因此,设法执行此操作的机器人的第一个实例将成功,而另一个实例将失败。机器人应该只处理消息并在此命令成功时作出响应。
(PX 30000
设置30秒到期,因此Redis没有充满这些密钥。)
这可以让您通过重叠正在运行的bot实例来进行零停机升级,而不必担心消息被处理两次。
请注意,如果以非优雅的方式关闭机器人,在此方案中仍然可以完全删除消息。 (它可能在调用SET
命令之后但在实际处理消息之前就死了。)一个具有两阶段“获取/删除”的真实队列会更好,但是你会回到我的另一个回答。 : - )
答案 1 :(得分:0)
我要考虑的一个想法是分成两个部分:
根据机器人的行为方式,它可以直接使用Web API,也可以将自己的消息放在&#34; queuer&#34;可以通过RTM API发送。
这个架构可能解决了你的问题...你现在可以在升级时简单地关闭机器人 - 响应只会延迟到新版本运行 - 或者你可以同时运行两个版本的机器人依赖队列的语义来防止两个版本都响应同一个消息。