RAbbitMQ With Python

download RAbbitMQ With Python

If you can't read please download the document

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 ###