![](/img/trans.png)
[英]Python Kombu consumer not notified of rabbitmq message (queue.get does work)
[英]Kombu, RabbitMQ: Ack message more than once in a consumer mixin
当我为Kombu记录新的SO文档项目时,我偶然发现了这个问题。
考虑以下消费者混合的 Kombu代码:
from kombu import Connection, Queue
from kombu.mixins import ConsumerMixin
from kombu.exceptions import MessageStateError
import datetime
# Send a message to the 'test_queue' queue
with Connection('amqp://guest:guest@localhost:5672//') as conn:
with conn.SimpleQueue(name='test_queue') as queue:
queue.put('String message sent to the queue')
# Callback functions
def print_upper(body, message):
print body.upper()
message.ack()
def print_lower(body, message):
print body.lower()
message.ack()
# Attach the callback function to a queue consumer
class Worker(ConsumerMixin):
def __init__(self, connection):
self.connection = connection
def get_consumers(self, Consumer, channel):
return [
Consumer(queues=Queue('test_queue'), callbacks=[print_even_characters, print_odd_characters]),
]
# Start the worker
with Connection('amqp://guest:guest@localhost:5672//') as conn:
worker = Worker(conn)
worker.run()
代码失败了:
kombu.exceptions.MessageStateError: Message already acknowledged with state: ACK
因为消息在print_even_characters()
和print_odd_characters()
上被print_even_characters()
两次。
一个简单的解决方案是仅确认最后一个回调函数,但如果我想在其他队列或连接上使用相同的函数,它会破坏模块性。
如何确认发送到多个回调函数的排队Kombu消息?
message.acknowledged
message.acknowledged
标志检查消息是否已经确认:
def print_upper(body, message):
print body.upper()
if not message.acknowledged:
message.ack()
def print_lower(body, message):
print body.lower()
if not message.acknowledged:
message.ack()
优点 :可读,简短。
缺点 :打破Python EAFP习语 。
def print_upper(body, message):
print body.upper()
try:
message.ack()
except MessageStateError:
pass
def print_lower(body, message):
print body.lower()
try:
message.ack()
except MessageStateError:
pass
优点:可读,Pythonic。
缺点:有点长 - 每回调4行样板代码。
该文档保证按顺序调用回调 。 因此,我们可以简单地.ack()
只进行最后一次回调:
def print_upper(body, message):
print body.upper()
def print_lower(body, message):
print body.lower()
message.ack()
优点:简短,可读,没有样板代码。
缺点:不是模块化的:除非最后一个回调始终是最后一个回调,否则其他队列不能使用回调。 这种隐式假设可能会破坏调用者代码。
这可以通过将回调函数移动到Worker
类中来解决。 我们放弃了一些模块化 - 这些功能不会从外部调用 - 而是获得安全性和可读性。
1和2之间的区别仅仅是风格问题。
如果执行顺序很重要,应该选择解决方案3,并且在成功完成所有回调之前是否应该确认消息。
如果始终应该确认消息,则应选择1或2,即使一个或多个回调失败也是如此。
请注意,还有其他可能的设计; 这个答案指的是驻留在worker之外的回调函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.