我正在尝试为rabbitmq添加延迟消息的一些功能。实际上我需要在2周后收到此消息。据我所知,我们不需要任何插件。此消息调用时,如何重新安排新的x延迟交换机,以便在2周内再次调用。我应该在哪里添加这个x延迟消息。
配置
"messageQueue": {
"connectionString": "amqp://guest:guest@localhost:5672?heartbeat=5",
"queueName": "history",
"exchange": {
"type": "headers",
"prefix": "history."
},
"reconnectTimeout": 5000
},
服务:
import amqplib from 'amqplib'
import config from 'config'
import logger from './logger'
const {reconnectTimeout, connectionString, exchange: {prefix, type: exchangeType}, queueName} = config.messageQueue
const onConsume = (expectedMessages, channel, onMessage) => async message => {
const {fields: {exchange}, properties: {correlationId, replyTo}, content} = message
logger.silly(`consumed message from ${exchange}`)
const messageTypeName = exchange.substring(exchange.startsWith(prefix) ? prefix.length : 0)
const messageType = expectedMessages[messageTypeName]
if (!messageType) {
logger.warn(`Unexpected message of type ${messageTypeName} received. The service only accepts messages of types `, Object.keys(expectedMessages))
return
}
const deserializedMessage = messageType.decode(content)
const object = deserializedMessage.toJSON()
const result = await onMessage(messageTypeName, object)
if (correlationId && replyTo) {
const {type, response} = result
const encoded = type.encode(response).finish()
channel.publish('', replyTo, encoded, {correlationId})
}
}
const startService = async (expectedMessages, onMessage) => {
const restoreOnFailure = e => {
logger.warn('connection with message bus lost due to error', e)
logger.info(`reconnecting in ${reconnectTimeout} milliseconds`)
setTimeout(() => startService(expectedMessages, onMessage), reconnectTimeout)
}
const exchanges = Object.keys(expectedMessages).map(m => `${prefix}${m}`)
try {
const connection = await amqplib.connect(connectionString)
connection.on('error', restoreOnFailure)
const channel = await connection.createChannel()
const handleConsume = onConsume(expectedMessages, channel, onMessage)
const queue = await channel.assertQueue(queueName)
exchanges.forEach(exchange => {
channel.assertExchange(exchange, exchangeType, {durable: true})
channel.bindQueue(queue.queue, exchange, '')
})
logger.debug(`start listening messages from ${exchanges.join(', ')}`)
channel.consume(queue.queue, handleConsume, {noAck: true})
}
catch (e) {
logger.warn('error while subscribing for messages message', e)
restoreOnFailure(e)
}
}
export default startService
答案 0 :(得分:1)
RabbitMQ有一个plug-in for scheduling messages。您可以使用它,但需遵守我在下面解释的重要设计警告。
使用步骤
您必须先安装它:
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
然后,您必须设置延迟交换:
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-delayed-type", "direct");
channel.exchangeDeclare("my-exchange", "x-delayed-message", true, false, args);
最后,您可以设置x-delay
参数(延迟以毫秒为单位)。
byte[] messageBodyBytes = "delayed payload".getBytes();
AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder();
headers = new HashMap<String, Object>();
headers.put("x-delay", 5000);
props.headers(headers);
channel.basicPublish("my-exchange", "", props.build(), messageBodyBytes);
两周等于(7*24*60*60*1000 = 604,800,000)
毫秒。
重要警告 正如我在this answer中解释的那样,要求消息代理做这件事真的很糟糕。
重要的是要记住,在处理消息队列时,它们在系统中执行非常特定的功能:在处理器忙于处理早期消息时保留消息。 预计正常运行的消息队列将尽快传递消息。基本上,基本的期望是一旦消息到达队列的头部,下一次拉动队列将产生消息 - 没有延迟。
延迟是带有队列的系统如何处理消息的结果。事实上,Little's Law提供了一些有趣的见解。如果你要在那里坚持一个任意的延迟,你真的不需要一个消息队列开始 - 你的所有工作都是预先安排的。
因此,在需要延迟的系统中(例如,加入/等待并行操作完成),您应该查看其他方法。通常,可查询数据库在此特定实例中是有意义的。如果您发现自己将消息保留在队列中预设的一段时间,那么您实际上是将消息队列用作数据库 - 这是一个它没有设计的功能。这不仅风险很大,而且很可能会损害您的消息代理的性能。