英文:
How can I acknowledge a Rabbitmq message using the message id only (in Go)?
问题
我构建了一个小型服务器(使用golang),用于从RabbitMQ中获取消息,并通过Websocket将其传递给连接的浏览器。虽然它工作得很好,但有一个注意事项:当通过websocket将消息传递给浏览器时,消息会被确认。对于大多数消息来说这没问题,但有些消息可能非常重要。如果用户的浏览器接收到这些消息,但用户没有看到消息,那么如果浏览器关闭或重新加载,消息将会丢失。是否有一种方法可以根据消息的消息ID(来自Delivery结构)在稍后的时间点确认消息?使用情况是:当用户显式确认消息时,某些消息会被确认,并且在那时将消息ID发送回工具以通过RabbitMQ进行确认。
英文:
I built a small server (golang) to grab messages from a RabbitMQ and deliver them to connected browsers via a Websocket.
It works quite well, though has one caveat: the messages are acknowledged when delivered to the browser via the websocket. For most messages that is ok but some messages might be very important. If the user's browser received those but the user didn't SEE the message, it would be lost if the browser was closed or reloaded.
Is there a way to ack a message at a later time based on its message id (from the Delivery struct)?
The use case would be that some messages are acked when the user acknowledges them explicitly and at that point the message id is sent back to the tool to be acknowledged with RabbitMQ.
答案1
得分: 2
即使你能做到这一点,这仍然是一个糟糕的设计。
如果用户没有看到消息会发生什么?你的Web服务器会一直保持连接吗?它会将消息“nack”回队列吗?
这两个选项都不好。
保留每条消息,RabbitMQ将开始出现来自许多用户的数千条未确认的消息的问题。将消息“nack”回队列,将会在Web服务器和RMQ服务器上不断循环地处理消息,同时还会增加两者之间的网络流量和CPU资源消耗。
解决这个问题的更好方法是,在从RabbitMQ中取出消息后,将其存储在数据库中。当消息被发送到/被浏览器查看时,更新数据库以反映这一点。
根据我撰写的一篇尚未发布的文章:
将消息存储在数据库中。
在数据库记录中添加一个字段,表示该消息属于哪个用户。当用户稍后重新连接时,查询数据库以获取该用户需要查看的任何消息,并在那时发送它们。
完整的过程如下:
- 用户的浏览器连接到Web服务器上的SignalR/Socket.io/Pusher/websockets
- Web服务器检查队列以获取在长时间运行的过程中发生的更新
- 当收到已登录用户的消息时
- 如果用户已登录,则通过WebSocket向用户广播消息
- 如果用户未登录,则将消息存储在数据库中
- 当用户再次登录时,查询数据库并发送所有等待的消息
这是在消息队列的概念出现之前你本应该做的事情,对吗?既然你现在有了消息队列,这应该是你现在要做的事情。
英文:
Even if you can do this, it's bad design.
What happens to the message if the user doesn't see it? Does your web server infinitely hang on to it? Does it "nack" the message back to the queue?
Neither of these options are good.
Hang on to every message, and RabbitMQ will start having issues with thousands of unacknowledged messages from a lot of users. Nack the message back to the queue and you'll thrash the message round in circles, spiking CPU resources on the web server and the RMQ server, as well as network traffic between the two.
The better solution to this problem is to store the message in a database, after pulling it out of RabbitMQ. When it gets sent to / viewed by the browser, update the database to reflect that.
From a yet-unpublished article I've written:
> Store the message in a database.
>
> Add a field to the database record that says who this message belongs
> to. When the user reconnects later, query the database for any
> messages that this user needs to see and send them along at that time.
>
> The full process started above, then becomes this:
>
> * User's browser connects to SignalR/Socket.io/Pusher/websockets on web
> server
> * Web server checks a queue for updates that happen during a long
> running process
> * When a message for a logged in user comes in
> * If the
> user is logged in, broadcast the message through the websocket to the
> user
> * If the user is not logged in, store the message in a database
> * When the user logs in again, query the database and send all waiting
> messages
>
> It's what you would have done before the idea of a message
> queue came in to play, right? It should be what you would do now that
> you have a message queue, as well.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论