[英]Kombu, RabbitMQ: Ack message more than once in a consumer mixin
I have stumbled upon this problem while I was documenting Kombu for the new SO documentation project. 当我为Kombu记录新的SO文档项目时,我偶然发现了这个问题。
Consider the following Kombu code of a Consumer Mixin : 考虑以下消费者混合的 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()
The code fails with: 代码失败了:
kombu.exceptions.MessageStateError: Message already acknowledged with state: ACK
Because the message was ACK-ed twice, on print_even_characters()
and print_odd_characters()
. 因为消息在print_even_characters()
和print_odd_characters()
上被print_even_characters()
两次。
A simple solution that works would be ACK-ing only the last callback function, but it breaks modularity if I want to use the same functions on other queues or connections. 一个简单的解决方案是仅确认最后一个回调函数,但如果我想在其他队列或连接上使用相同的函数,它会破坏模块性。
How to ACK a queued Kombu message that is sent to more than one callback function? 如何确认发送到多个回调函数的排队Kombu消息?
message.acknowledged
1 - 检查message.acknowledged
The message.acknowledged
flag checks whether the message is already ACK-ed: 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()
Pros : Readable, short. 优点 :可读,简短。
Cons : Breaks Python EAFP idiom . 缺点 :打破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
Pros: Readable, Pythonic. 优点:可读,Pythonic。
Cons: A little long - 4 lines of boilerplate code per callback. 缺点:有点长 - 每回调4行样板代码。
The documentation guarantees that the callbacks are called in order . 该文档保证按顺序调用回调 。 Therefore, we can simply .ack()
only the last callback: 因此,我们可以简单地.ack()
只进行最后一次回调:
def print_upper(body, message):
print body.upper()
def print_lower(body, message):
print body.lower()
message.ack()
Pros: Short, readable, no boilerplate code. 优点:简短,可读,没有样板代码。
Cons: Not modular: the callbacks can not be used by another queue, unless the last callback is always last. 缺点:不是模块化的:除非最后一个回调始终是最后一个回调,否则其他队列不能使用回调。 This implicit assumption can break the caller code. 这种隐式假设可能会破坏调用者代码。
This can be solved by moving the callback functions into the Worker
class. 这可以通过将回调函数移动到Worker
类中来解决。 We give up some modularity - these functions will not be called from outside - but gain safety and readability. 我们放弃了一些模块化 - 这些功能不会从外部调用 - 而是获得安全性和可读性。
The difference between 1 and 2 is merely a matter of style. 1和2之间的区别仅仅是风格问题。
Solution 3 should be picked if the order of execution matters, and whether a message should not be ACK-ed before it went through all the callbacks successfully. 如果执行顺序很重要,应该选择解决方案3,并且在成功完成所有回调之前是否应该确认消息。
1 or 2 should be picked if the message should always be ACK-ed, even if one or more callbacks failed. 如果始终应该确认消息,则应选择1或2,即使一个或多个回调失败也是如此。
Note that there are other possible designs; 请注意,还有其他可能的设计; this answer refers to callback functions that reside outside the worker. 这个答案指的是驻留在worker之外的回调函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.