This document is for Kombu's development version, which can be significantly different from previous releases. Get the stable docs here: 5.0.
Consumers¶
Basics¶
The Consumer
takes a connection (or channel) and a list of queues to
consume from. Several consumers can be mixed to consume from different
channels, as they all bind to the same connection, and drain_events
will
drain events from all channels on that connection.
Note
Kombu since 3.0 will only accept json/binary or text messages by default,
to allow deserialization of other formats you have to specify them
in the accept
argument (in addition to setting the right content type for your messages):
>>> Consumer(conn, accept=['json', 'pickle', 'msgpack', 'yaml'])
You can create a consumer using a Connection. This consumer is consuming from a single queue with name ‘queue’:
>>> queue = Queue('queue', routing_key='queue')
>>> consumer = connection.Consumer(queue)
You can also instantiate Consumer directly, it takes a channel or a connection as an argument. This consumer also consumes from single queue with name ‘queue’:
>>> queue = Queue('queue', routing_key='queue')
>>> with Connection('amqp://') as conn:
... with conn.channel() as channel:
... consumer = Consumer(channel, queue)
A consumer needs to specify a handler for received data. This handler is specified in the form of a callback. The callback function is called
by kombu every time a new message is received. The callback is called with two parameters: body
, containing deserialized
data sent by a producer, and a Message
instance message
. The user is responsible for acknowledging messages when manual
acknowledgement is set.
>>> def callback(body, message):
... print(body)
... message.ack()
>>> consumer.register_callback(callback)
Draining events from a single consumer¶
The method drain_events
blocks indefinitely by default. This example sets the timeout to 1 second:
>>> with consumer:
... connection.drain_events(timeout=1)
Draining events from several consumers¶
Each consumer has its own list of queues. Each consumer accepts data in ‘json’ format:
>>> from kombu.utils.compat import nested
>>> queues1 = [Queue('queue11', routing_key='queue11'),
Queue('queue12', routing_key='queue12')]
>>> queues2 = [Queue('queue21', routing_key='queue21'),
Queue('queue22', routing_key='queue22')]
>>> with connection.channel(), connection.channel() as (channel1, channel2):
... with nested(Consumer(channel1, queues1, accept=['json']),
... Consumer(channel2, queues2, accept=['json'])):
... connection.drain_events(timeout=1)
The full example will look as follows:
from kombu import Connection, Consumer, Queue
def callback(body, message):
print('RECEIVED MESSAGE: {0!r}'.format(body))
message.ack()
queue1 = Queue('queue1', routing_key='queue1')
queue2 = Queue('queue2', routing_key='queue2')
with Connection('amqp://') as conn:
with conn.channel() as channel:
consumer = Consumer(conn, [queue1, queue2], accept=['json'])
consumer.register_callback(callback)
with consumer:
conn.drain_events(timeout=1)
Consumer mixin classes¶
Kombu provides predefined mixin classes in module mixins
. It contains two classes:
ConsumerMixin
for creating consumers and ConsumerProducerMixin
for creating consumers supporting also publishing messages. Consumers can be created just by subclassing
mixin class and overriding some of the methods:
from kombu.mixins import ConsumerMixin
class C(ConsumerMixin):
def __init__(self, connection):
self.connection = connection
def get_consumers(self, Consumer, channel):
return [
Consumer(channel, callbacks=[self.on_message], accept=['json']),
]
def on_message(self, body, message):
print('RECEIVED MESSAGE: {0!r}'.format(body))
message.ack()
C(connection).run()
and with multiple channels again:
from kombu import Consumer
from kombu.mixins import ConsumerMixin
class C(ConsumerMixin):
channel2 = None
def __init__(self, connection):
self.connection = connection
def get_consumers(self, _, default_channel):
self.channel2 = default_channel.connection.channel()
return [Consumer(default_channel, queues1,
callbacks=[self.on_message],
accept=['json']),
Consumer(self.channel2, queues2,
callbacks=[self.on_special_message],
accept=['json'])]
def on_consume_end(self, connection, default_channel):
if self.channel2:
self.channel2.close()
C(connection).run()
The main use of ConsumerProducerMixin
is to create consumers
that need to also publish messages on a separate connection (e.g. sending rpc
replies, streaming results):
from kombu import Producer, Queue
from kombu.mixins import ConsumerProducerMixin
rpc_queue = Queue('rpc_queue')
class Worker(ConsumerProducerMixin):
def __init__(self, connection):
self.connection = connection
def get_consumers(self, Consumer, channel):
return [Consumer(
queues=[rpc_queue],
on_message=self.on_request,
accept={'application/json'},
prefetch_count=1,
)]
def on_request(self, message):
n = message.payload['n']
print(' [.] fib({0})'.format(n))
result = fib(n)
self.producer.publish(
{'result': result},
exchange='', routing_key=message.properties['reply_to'],
correlation_id=message.properties['correlation_id'],
serializer='json',
retry=True,
)
message.ack()
See also
examples/rpc-tut6/
in the Github repository.
Advanced Topics¶
RabbitMQ¶
Consumer Priorities¶
RabbitMQ defines a consumer priority extension to the amqp protocol,
that can be enabled by setting the x-priority
argument to
basic.consume
.
In kombu you can specify this argument on the Queue
, like
this:
queue = Queue('name', Exchange('exchange_name', type='direct'),
consumer_arguments={'x-priority': 10})
Read more about consumer priorities here: https://www.rabbitmq.com/consumer-priority.html