RAbbitMQ With Python

Post on 29-Dec-2015

24 views 0 download

description

test

Transcript of RAbbitMQ With Python

Notes on using Python amqplib For more detailed descriptions of AMQP concepts, visit https://jira.amqp.org/confluence/display/AMQP/Download This doc just covers some example usages of the Python library. +---------------------------------------------------------------| | IMPORTANT!! - Connections are NOT thread-safe. A multithreaded | Python program can only use amqplib as long as | each thread has its own Connection object, and | does not try to share amqplib objects such as | Connections or Channels with other threads. | +---------------------------------------------------------------Importing the client -------------------This library currently supports the AMQP 0-8 spec, importing a module geared towards that spec can be done with something like: import amqplib.client_0_8 as amqp Connections ---------A connection object represents a network connection to the server. Some examples for creating a Connection object: conn conn conn conn conn conn conn = = = = = = = amqp.Connection() amqp.Connection('1.2.3.4') amqp.Connection('::1') # IPv6 amqp.Connection('[1234::1]:5671') # IPv6 amqp.Connection('foobar.edu:5671') # could be IPv4 or IPv6 amqp.Connection(host='1.2.3.4:5671', ssl=True) amqp.Connection(userid='foo', password='bar')

Fancier SSL options are available with Python >= 2.6 by specifying a dictionary of options as the "ssl" parameter (see the standard Python library ssl.wrap_socket() function documentation) import ssl conn = amqp.Connection(host='1.2.3.4:5671', ssl={ 'ca_certs': '/path/to/cacert.pem', 'keyfile' : '/path/to/key.pem', 'certfile': '/path/to/cert.pem', 'cert_reqs': ssl.CERT_REQUIRED, }) Connections are closed with the close() method conn.close() Channels ---------Once a Connection is open, one or more Channel objects may be

opened, acting as virtual connections between peers. Channels are where most of the action is. ch = conn.channel(1) # create and open channel with a specific numeric id ch2 = conn.channel() # let amqplib assign a channel number print 'my channel is', ch2.channel_id ch3 = conn.channel(1) # since channel 1 is already created and open, just # return another reference to that. Channels have a close() method too, which doesn't affect other channels ch2.close() +---------------------------------------------------------------| | IMPORTANT!! - be sure to close your channels or connection | if you've been calling async methods like | basic_publish() - to ensure your messages are | actually flushed out the TCP socket before the | program ends, instead of potentially being lost. | +---------------------------------------------------------------Connections and Channels will close automatically when used as context managers in 'with' statements (available in Python 2.5 or higher). For example: with Connection('1.2.3.4') as conn: with conn.channel() as ch: # # Do some stuff... # ch.basic_publish(blah, blah, blah) # When this point is reached, the Channel will have been # closed for you. # When this point is reached, the Connection will have been # closed for you. Access Tickets -------------Before a channel can do much else, it needs an access ticket, specifying a 'realm', and the actions it wants to perform on that realm. tkt = ch.access_request('/data', active=True, write=True, read=True) ch.exchange_declare('myfan', 'fanout', auto_delete=True, ticket=tkt) The most recently requested ticket is saved in the Channel object, and used as a default value for other methods that require tickets. So it's not necessary to manually keep and pass it around. A simpler version of the above code is: ch.access_request('/data', active=True, write=True, read=True) ch.exchange_declare('myfan', 'fanout', auto_delete=True)

Messages --------This library only supports the Basic Content type, although the class was named 'Message' based on what's coming in the 0-10 spec. A Message can be created as simply as msg = amqp.Message('hello world') Unicode bodies are converted to UTF-8 and the 'content_encoding' property is automatically set to 'UTF-8', so these two Messages are equivalent msg1 = amqp.Message(u'Unicode hello') msg2 = amqp.Message(u'Unicode hello'.encode('utf-8'), content_encoding='UTF8') Messages may have an 'application_headers' dictionary (another 0-10ism, 0-8 just calls the property 'headers'), consisting of string keys and values that are strings, integers, Decimal (a bit shaky), datetime.datetime, and other dictionaries containing those same types. msg = amqp.Message('fancy', application_headers={'foo': 7, 'bar': 'baz'}) Exchanges & Queues ------------------In the AMQP model, publishers send messages to exchanges, which then distribute them to queues, which deliver them to receivers. AMQP defines some default exchanges such as, 'amq.direct', 'amq.topic', 'amq.fanout' - which can be used right away. To send to one of these default exchanges: ch.basic_publish(msg, 'amq.fanout') To declare your own exchange and send it a message: ch.exchange_declare('myfan', type='fanout') ch.basic_publish(msg, 'myfan') To receive messages, a program must declare a queue, and bind it to an exchange: ch.queue_declare('myqueue') ch.queue_bind('myqueue', 'amq.fanout') If the queue name is omitted from the queue_declare() method, a unique one is generated by the server and returned (along with message_count and consumer_count values which we don't care about in this case). qname, _, _ = ch.queue_declare() ch.queue_bind(qname, 'amq.fanout') Receiving Messages -----------------Once a queue is bound to an exchange, messages can be received either by polling or by waiting on the channel. Polling with basic_get() immediately returns either a Message object, or

None if no messages are available: msg = ch.basic_get('myqueue') if msg is not None: # do something ch.basic_ack(msg.delivery_tag) Received messages are acknowledged with the Channel.basic_ack() method unless we called basic_get() with a no_ack=True parameter. To block and wait for messages, use basic_consume() with a callback function, and then wait() on the channel. The AMQP server will deliver messages to the channel as they're placed into the queue. def mycallback(msg): print 'received', msg.body, 'from channel #', msg.channel.channel_id ch.basic_consume('myqueue', callback=mycallback, no_ack=True) while True: ch.wait() The above example will loop forever. To cancel the 'consume', use basic_cancel() with a consumer_tag. A consumer_tag is a string that's either specified when you call basic_consume() ch.basic_consume('myqueue', callback=mycallback, consumer_tag='mytag') ... ch.basic_cancel('mytag') or uniquely generated by the server. tag = ch.basic_consume('myqueue', callback=mycallback) ... ch.basic_cancel(tag) The consumer_tag is also included as a property in any Message objects delivered through a callback. msg.channel.basic_cancel(msg.consumer_tag) A Channel object has a 'callbacks' property that can be checked to see if there are any outstanding basic_consume() operations registered. The demo/demo_send.py script uses this to allow for breaking out of a waiting loop cleanly. ### EOF ###