[rabbitmq-discuss] pika and node.amqp interop

Michael Bridgen mikeb at rabbitmq.com
Sat Jan 22 10:46:48 GMT 2011


Hi Dan,

> I am new to rabbitmq. I got the python "getting started" examples to
> work just fine.
> I would like to be able to send messages between node.js (using
> node.amqp) and python/pika.
 >
> I can successfully receive a message in node.js using this code:
>
> [receiver - node.js]
> var sys = require('sys');
> var amqp = require('./amqp');
>
> var connection = amqp.createConnection({ host: 'localhost' });
>
> // Wait for connection to become established.
> connection.addListener('ready', function () {
>    // Create a queue and bind to all messages.
>    // Use the default 'amq.topic' exchange
>
>    var q = connection.queue('my-queue');
>    // Catch all messages
>    q.bind('#');
>
>    // Receive messages
>    q.subscribe(function (message) {
>      // Print messages to stdout
>      sys.puts(sys.inspect(message));
>    });
> });
>
> [sender - python/pika]
> #!/usr/bin/env python
> import pika
>
> connection = pika.AsyncoreConnection(pika.ConnectionParameters(
>          host='localhost'))
> channel = connection.channel()
>
>
> channel.basic_publish(exchange='',
>                        routing_key='my-queue',
>                        body='Hello World!')
> print " [x] Sent 'Hello World!'"
> connection.close()

You should be aware that node-amqp, at least Ryan's original and most 
forks of it, make some unorthodox choices for parameter defaults and 
behaviour, which to be fair are probably inherited from the EventMachine 
AMQP client.

In particular, the exchange that's published or bound to, if none is 
given, is "amq.topic".  This is directly at odds with AMQP, for which an 
empty exchange name means the "default exchange" defined in the 
specification; that is, route directly to the queue named in the routing 
key.

So your example above is working by coincidence -- you don't need to 
bind the queue in the node.js code, since your Python code is 
effectively sending straight to the queue.  I.e., the node.js code sets up

(amq.topic) --"#"--> [ | | my-queue | | ]

but the message sent in the Python code actually follows

(default) --"my-queue"--> [ | | my-queue | | ]

> But I can't go the other way. I'm not sure that the message sent by
> node.js is going anywhere. I've looked at the unit tests for node.amqp
> (they all pass) but there is something I am missing, probably to do with
> exchanges or something. I'd like to do something like this:
>
> [sender - node.js]
> var sys = require('sys');
> var amqp = require('./amqp');
>
> var connection = amqp.createConnection({ host: 'localhost' });
>
> // Wait for connection to become established.
> connection.addListener('ready', function () {
>    // Create a queue and bind to all messages.
>    // Use the default 'amq.topic' exchange
>    connection.publish("my-queue", {random_key:"this is my message"});
>    connection.end();
> });
>
> [receiver - python/pika]
> #!/usr/bin/env python
> import pika
> import sys
>
> connection = pika.AsyncoreConnection(pika.ConnectionParameters(
>          host='localhost'))
> channel = connection.channel()
>
> print ' [*] Waiting for messages. To exit press CTRL+C'
>
> def callback(ch, method, properties, body):
>      print body,
>      sys.stdout.flush()
> channel.basic_consume(callback,
>                        queue='my-queue',
>                        no_ack=True)
>
> pika.asyncore_loop()

This way around (presuming there's a restart in-between runs), node.js 
sends to amq.topic, but nothing is bound there, so the message is discarded.

You might try binding the queue, in the Python, to the exchange 
"amq.topic".  You should probably also declare it.

If you actually don't want to use "amq.topic", and you probably don't if 
you can help it, you might declare your own exchange and use that.

I'm not sure there's a way to send to the default exchange in node-amqp. 
  I fixed this, and some other things, in my fork, but it's a bit behind 
the curve at the minute.
http://github.com/squaremo/node-amqp

> But nothing happens.
>
> Another thing (possibly related?) that I run into is if I create a queue
> in python using, e.g.:
>
> channel.queue_declare(queue='hello')
>
> Then, in node.js, when I do:
>
>    var q = connection.queue('hello');
>
> I get this:
>
> Unhandled channel error: PRECONDITION_FAILED - parameters for queue
> 'hello' in vhost '/' not equivalent
>
> events:12
>          throw arguments[1];
>                         ^
> Error: PRECONDITION_FAILED - parameters for queue 'hello' in vhost '/'
> not equivalent
>      at Queue._onMethod
> (/Users/dtenenba/dev/dev-amqp/node-amqp/amqp.js:1390:15)
>      at Connection._onMethod
> (/Users/dtenenba/dev/dev-amqp/node-amqp/amqp.js:784:28)
>      at AMQPParser.onMethod
> (/Users/dtenenba/dev/dev-amqp/node-amqp/amqp.js:698:12)
>      at AMQPParser._parseMethodFrame
> (/Users/dtenenba/dev/dev-amqp/node-amqp/amqp.js:415:10)
>      at AMQPParser.execute
> (/Users/dtenenba/dev/dev-amqp/node-amqp/amqp.js:196:20)
>      at Connection.<anonymous>
> (/Users/dtenenba/dev/dev-amqp/node-amqp/amqp.js:731:12)
>      at Connection.emit (events:31:17)
>      at IOWatcher.callback (net:489:16)
>      at node.js:773:9
>
> It appears that python's idea of a 'hello' queue is different from that
> of node.amqp's. How can I do this so that I don't receive this error?

You can provide explicit values for the other parameters; that is (with 
parameter names from memory ..),

[node.js]
var q = connection.queue("hello",
           { autoDelete: true, durable: false, exclusive: false });

[Python]
q = channel.queue_declare(queue='hello',
                           auto_delete=true,
                           durable=false,
                           exclusive=false)


I suspect the libraries differ only in the default value for 
auto-delete, so supplying that may be enough.

> Hope this is the right place for this question. If not please tell me
> where I should post it.

This is a good place.

Regards,
Michael


More information about the rabbitmq-discuss mailing list