我正在创建一个简单的聊天应用程序
{
//Creating a new connection
amqp.connect('amqp://localhost', (err, conn) => {
conn.createChannel(function(err, ch) {
ch.assertExchange(exchangeName, 'direct', { durable: false });
const routingKey = // some routing key;
wss.on('connection', (ws, req) => {
// Creating a new queue for the user
ch.assertQueue('', { exclusive: true, persist: true, durable: true }, (err, q) => {
// Binds with the routing key
ch.bindQueue(q.queue, exchangeName, routingKey);
ch.consume(q.queue, (msg) => {
if (ws.readyState === 1) {
ch.ack(msg);
ws.send(` [-] Received ${msg.content.toString()}`);
} else {
// What will come here so that it will be requeued to a new queue with the same routing id?
}
}, { noAck: false });
});
ws.on('message', (message) => {
ch.publish(exchangeName, routingKey, new Buffer(message));
console.log(`[x] Sent ${message} to the exchange with routingKey ${routingKey}`);
});
})
当所有用户都在与服务器连接的插槽中时,这可以正常工作。我要实现的是当套接字连接丢失给用户时,如果他错过了基于路由密钥(特定于用户)的消息,那么只要他重新连接到其他队列,他就应该能够再次接收到这些消息。我认为这是可能的,因为如果在任何队列中未确认消息,则可以交换消息。但不确定如何实现。
答案 0 :(得分:1)
让我解决几个误解...
我要实现的是当套接字连接死于 用户以及他是否错过了基于路由密钥的消息(特定于 用户),那么他应该能够在任何时候再次收到这些消息 他重新连接到另一个队列
您正在使用互斥队列。 根据定义,当这些队列的关联连接和通道消失时,这些队列将被删除。删除队列后,这些队列中的消息就会丢失。
我认为这是可能的,因为如果 它不会在任何队列中得到确认。
RabbitMQ不是这样工作的。交换用于路由消息,而队列则是存储消息的地方。
以下评论不正确:
如果user1和user2在不同的主机上,则显然他们应该建立 不同的渠道。 “渠道”就像连接一样,如果 两个通道使用相同的队列,它们可以接收相同的消息。
user1
和user2
位于不同的主机上,并且可能在不同的进程中运行,它们各自将建立自己的连接和通道。两个使用者将从不从同一队列中接收相同的消息。
回到最初的问题,您需要将队列声明为非-排他性和持久性,并以这样的方式命名队列:当您的应用程序重新连接时,该应用程序将连接到同一队列队列。这样,应用程序可以使用队列中剩余的消息。
有多种方法让RabbitMQ为您删除documented的未使用队列。
注意: RabbitMQ团队监视rabbitmq-users
mailing list,并且有时仅在StackOverflow上回答问题。
答案 1 :(得分:0)
消费者应该使用带有确认的消息来消费消息,如果消息传递给使用者并且在断开消费者连接之前未得到确认,那么RabbitMQ将重新传递它。您可以从RabbitMQ doc获取更多详细信息。
在您的情况下,当套接字连接断开时,您应强制关闭通道,然后RabbitMQ将知道这些消息应重新发送。
为确保消息在服务器重新启动后仍然存在,请将交换设置为“持久”:
ch.assertExchange(exchangeName, 'direct', { durable: false });