我正在构建一种微服务应用程序,并使用RabbitMQ在我的服务之间进行通信。
我有一个nodeJS应用程序,它应该从RabbitMQ接收消息并在特定消息进入时执行命令。所以这是以下代码的作用:
symfony_messages
队列product.created
标识的邮件进入,则脚本使用spawn
中的child_process
执行特定命令。我的问题是:有时候,我会重新开始"我的剧本如何确保在重新启动脚本时不处理事件?如何确保流程不会消耗消息并在产生流程之前停止?
我想到的可能解决方案是:
以下是代码(如果您已经提出问题则不需要阅读):
const amqp = require('amqplib/callback_api')
const { spawn } = require('child_process')
amqp.connect('amqp://guest:guest@127.0.0.1:5672', (err, conn) => {
if (err) {
console.log(err)
return
}
conn.createChannel((err, channel) => {
let q = 'symfony_messages'
channel.assertQueue(q, {
durable: false
})
console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", q);
channel.consume(q, (msg) => {
let event = JSON.parse(msg.content.toString())
if (event.name === 'product.created') {
console.log('Indexing order...')
let cp = spawn('php', [path.join(__dirname, '..', '..', 'bin', 'console'), 'elastic:index:orders', event.payload.product_id])
cp.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
})
cp.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
})
cp.on('close', (code) => {
console.log(`child process exited with code ${code}`);
})
}
}, {noAck: true});
})
})
答案 0 :(得分:2)
一旦消息成功处理,在消息上使用channel.ack(消息)功能不是一个好的模式吗?您已将noAck选项设置为true,但您可以使用ACK机制确保仅在成功处理消息后才将消息从队列中取出。
同样,您可以使用Nack函数故意告诉RabbitMQ消息未被处理,我通常在进程函数错误处理程序(或promise.catch)中执行此操作。
我在将消息写入数据库的服务中使用类似的机制。我只在消息写入db后才确认消息。在RabbitMQ中设置死信交换/队列也很有用,这样任何Nacked消息都会在那里结束。然后,您可以检查这些消息并查看无法处理的消息(或者在导致问题的错误情况得到解决后自动尝试重新处理。)