Node.js 未在RabbitMQ和使用AMQP.Node的节点中使用死信消息
我想在一段时间后在我的一名员工身上收到一条消息。在发现所谓的死信交换后,我决定使用Node和RabbitMQ 消息似乎已被发送到DeadExchange中的队列,但在WorkExchange中的工作队列中经过一段时间后,使用者从未收到消息。要么绑定队列已关闭,要么死信队列不工作 我现在尝试了很多不同的价值观。有人能指出我遗漏了什么吗Node.js 未在RabbitMQ和使用AMQP.Node的节点中使用死信消息,node.js,rabbitmq,dead-letter,Node.js,Rabbitmq,Dead Letter,我想在一段时间后在我的一名员工身上收到一条消息。在发现所谓的死信交换后,我决定使用Node和RabbitMQ 消息似乎已被发送到DeadExchange中的队列,但在WorkExchange中的工作队列中经过一段时间后,使用者从未收到消息。要么绑定队列已关闭,要么死信队列不工作 我现在尝试了很多不同的价值观。有人能指出我遗漏了什么吗 var amqp = require('amqplib'); var url = 'amqp://dev.rabbitmq.com'; amqp.connect(
var amqp = require('amqplib');
var url = 'amqp://dev.rabbitmq.com';
amqp.connect(url).then(function(conn) {
//Subscribe to the WorkQueue in WorkExchange to which the "delayed" messages get dead-letter'ed (is that a verb?) to.
return conn.createChannel().then(function(ch) {
return ch.assertExchange('WorkExchange', 'direct').then(function() {
return ch.assertQueue('WorkQueue', {
autoDelete: false,
durable: true
})
}).then(function() {
return ch.bindQueue('WorkQueue', 'WorkExchange', '');
}).then(function() {
console.log('Waiting for consume.');
return ch.consume('WorkQueue', function(msg) {
console.log('Received message.');
console.log(msg.content.toString());
ch.ack(msg);
});
});
})
}).then(function() {
//Now send a test message to DeadExchange to a random (unique) queue.
return amqp.connect(url).then(function(conn) {
return conn.createChannel();
}).then(function(ch) {
return ch.assertExchange('DeadExchange', 'direct').then(function() {
return ch.assertQueue('', {
arguments: {
'x-dead-letter-exchange': 'WorkExchange',
'x-message-ttl': 2000,
'x-expires': 10000
}
})
}).then(function(ok) {
console.log('Sending delayed message');
return ch.sendToQueue(ok.queue, new Buffer(':)'));
});
})
}).then(null, function(error) {
console.log('error\'ed')
console.log(error);
console.log(error.stack);
});
我正在使用amqp.node(),它是npm中的amqplib。尽管node amqp()似乎更受欢迎,但它并没有实现完整的协议,并且在重新连接方面存在一些悬而未决的问题
dev.rabbitmq.com正在运行rabbitmq 3.1.3。刚刚修复的AMQP.Node中的通道#assertQueue中存在错误,请参阅。修复程序在GitHub上,但还没有在npm中。这是一个工作代码。当消息在DeadExchange中花费的时间超过ttl时,它将被推送到WorkExchange。成功的关键是定义正确的路由密钥。要向其发送post ttl的exchange队列应使用路由键(注意:不是默认值)进行绑定,并且“x-dead-letter-routing-key”属性值应与该路由键匹配
var amqp=require('amqplib');
var url='1〕amqp://localhost';
amqp.connect(url).then(函数(conn){
//订阅WorkExchange中的工作队列,“延迟”消息将以死信形式发送到该队列(这是动词吗?)。
返回连接createChannel().then(函数(ch){
返回ch.assertExchange('WorkExchange','direct')。然后返回(function(){
返回ch.assertQueue('工作队列'{
自动删除:false,
持久的:真的
})
}).然后(函数(){
返回ch.bindQueue('WorkQueue','WorkExchange','rk1');
}).然后(函数(){
log('等待消费');
返回ch.consume('WorkQueue',函数(msg){
log('收到的消息');
log(msg.content.toString());
ch.ack(msg);
});
});
})
}).然后(函数(){
//现在将测试消息发送到DeadExchange到DEQ队列。
返回amqp.connect(url)。然后返回(函数(conn){
返回连接createChannel();
}).然后(功能(ch){
返回ch.assertExchange('DeadExchange','direct')。然后(function(){
返回ch.assertQueue('DEQ'{
论据:{
“x-dead-letter-exchange”:“WorkExchange”,
“x-dead-letter-routing-key”:“rk1”,
“x-message-ttl”:15000,
“x-expires”:100000
}
})
}).然后(函数(){
返回ch.bindQueue('DEQ','DeadExchange','');
}).然后(函数(){
console.log(“发送延迟消息”);
返回ch.publish('DeadExchange','',新缓冲区('Over the Hills and Far Away!'));
});
})
}).then(空,函数(错误){
console.log('错误'ed')
console.log(错误);
console.log(error.stack);
});代码>下面是一个使用AMQP连接管理器管理节点的示例。我注意到没有任何示例与我们在代码中所做的操作相匹配,因此我用一个简单的示例和一个通过重新发布到主exchange的重试次数进行了回购:
下面是一个简单的例子:
const amqp = require('amqp-connection-manager');
const username = encodeURIComponent('queue');
const password = encodeURIComponent('pass');
const port = '5672';
const host = 'localhost';
const connectionString = `amqp://${username}:${password}@${host}:${port}`;
// Ask the connection manager for a ChannelWrapper. Specify a setup function to
// run every time we reconnect to the broker.
connection = amqp.connect([connectionString]);
// A channel is your ongoing connection to RabbitMQ.
// All commands go through your channel.
connection.createChannel({
json: true,
setup: function (channel) {
channel.prefetch(100);
// Setup EXCHANGES - which are hubs you PUBLISH to that dispatch MESSAGES to QUEUES
return Promise.all([
channel.assertExchange('Test_MainExchange', 'topic', {
durable: false,
autoDelete: true,
noAck: false
}),
channel.assertExchange('Test_DeadLetterExchange', 'topic', {
durable: false,
autoDelete: true,
maxLength: 1000,
noAck: true // This means dead letter messages will not need an explicit acknowledgement or rejection
})
])
// Setup QUEUES - which are delegated MESSAGES by EXCHANGES.
// The MESSAGES then need to be CONSUMED.
.then(() => {
return Promise.all([
channel.assertQueue(
'Test_MainQueue',
options = {
durable: true,
autoDelete: true,
exclusive: false,
messageTtl: 1000*60*60*1,
deadLetterExchange: 'Test_DeadLetterExchange'
}
),
channel.assertQueue('Test_DeadLetterQueue',
options = {
durable: false,
autoDelete: true,
exclusive: false
}
)
]);
})
// This glues the QUEUES and EXCHANGES together
// The last parameter is a routing key. A hash/pound just means: give me all messages in the exchange.
.then(() => {
return Promise.all([
channel.bindQueue('Test_MainQueue', 'Test_MainExchange', '#'),
channel.bindQueue('Test_DeadLetterQueue', 'Test_DeadLetterExchange', '#')
]);
})
// Setup our CONSUMERS
// They pick MESSAGES off of QUEUES and do something with them (either ack or nack them)
.then(() => {
return Promise.all([
channel.consume('Test_MainQueue', (msg) => {
const stringifiedContent = msg.content ? msg.content.toString() : '{}';
console.log('Test_MainQueue::CONSUME ' + stringifiedContent);
const messageData = JSON.parse(stringifiedContent);
if (messageData.value === 0) {
console.log('Test_MainQueue::REJECT ' + stringifiedContent);
// the 'false' param at the very end means, don't retry! dead letter this instead!
return channel.nack(msg, true, false);
}
return channel.ack(msg);
})
]),
channel.consume('Test_DeadLetterQueue', (msg) => {
const stringifiedContent = msg.content ? msg.content.toString() : '{}';
console.log('');
console.log('Test_DeadLetterQueue::CONSUME ' + stringifiedContent);
console.log('');
});
})
.then(() => {
setInterval(function () {
const messageData = {
text: 'Dead letter if 0',
value: Math.floor(Math.random()*5)
};
const stringifiedMessage = JSON.stringify(messageData);
// Publish message to exchange
if (channel.publish('Test_MainExchange', '', new Buffer(stringifiedMessage))) {
console.log(`Sent ${stringifiedMessage}`);
} else {
console.log(`Failed to send ${stringifiedMessage}`);
};
}, 300);
});
}
});
你能详细说明一下你想要达到的目标吗?现在还不完全清楚使用死信交换的目的是什么……目前,我的工作人员每2秒轮询一次数据库,检查事件是否结束(然后做一些事情,比如更新几个集合,通知另一个队列通过SSE向客户端发送消息)。现在,我想发送一条死信消息,该消息在我的工作人员收听的工作队列(经过特定时间后)中结束。这将从数据库中删除负载,并允许我更轻松地进行扩展。常规的RabbitMQ消息可以正常工作,但死信交换则不行。有什么想法吗?请注意:工作队列中的使用者从未收到消息。