消息确认
完成一项任务可能需要几秒钟。您可能想知道,如果其中一个消费者开始了一项长期任务并且只完成了部分任务而死亡,会发生什么。使用我们当前的代码,一旦 RabbitMQ 将消息传递给客户,它就会立即将其从内存中删除。在这种情况下,如果你杀死一个工人,我们将丢失它刚刚处理的消息。我们还将丢失所有已分派给该特定工作人员但尚未处理的消息。
但我们不想丢失任何任务。如果一个工人死了,我们希望将任务交付给另一个工人。
为了确保消息永远不会丢失,RabbitMQ 支持消息确认。一个 ack(nowledgement) 从消费者发回,告诉 RabbitMQ 一个特定的消息已经被接收、处理并且 RabbitMQ 可以自由地删除它。
如果消费者在没有发送 ack 的情况下死亡(其通道关闭、连接关闭或 TCP 连接丢失),RabbitMQ 将理解消息未完全处理并将重新排队。如果有其他消费者同时在线,它会迅速将其重新交付给另一个消费者。这样您就可以确保不会丢失任何消息,即使工作人员偶尔会死亡。
没有任何消息超时;RabbitMQ 会在消费者死亡时重新传递消息。即使处理消息需要非常非常长的时间也没关系。
默认情况下启用消息确认。在前面的例子中,我们通过no_ack=True标志明确地关闭了它们。一旦我们完成了一项任务,是时候移除这个标志并向工作人员发送适当的确认了。
async def on_message(message: IncomingMessage):
print(" [x] Received %r" % message.body)
await asyncio.sleep(message.body.count(b’.’), loop=loop)
print(" [x] Done")
message.ack()
或使用特殊的上下文处理器:
def on_message(message: IncomingMessage):
async with message.process(requeue=True):
print(" [x] Received message %r" % message)
print(" Message body is: %r" % message.body)
如果上下文处理器将捕获异常,则消息将返回到队列。
使用此代码,我们可以确保即使您在处理消息时使用 CTRL+C 杀死工作人员,也不会丢失任何内容。工人死后不久,所有未确认的消息都将重新传递。