Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarification of "message type" in handlers #48

Closed
jhaugh42 opened this issue Feb 27, 2015 · 2 comments
Closed

Clarification of "message type" in handlers #48

jhaugh42 opened this issue Feb 27, 2015 · 2 comments

Comments

@jhaugh42
Copy link

First, thank you for this library!

I have a question about how the handlers are able to handle messages based on the type property.

Calling handle returns a subscription:

var subscription = rabbit.handle('published', function (message) {
        console.log(JSON.stringify(message.body));
    });

The first parameter of handle is referred to as message type. In the subscription returned, I see that the subscription's topic field is set to the value that was passed for type. This appears confusing, though this could be because I do not fully understand the nomenclature.

I eventually discovered that no matter what I chose to use for message type, none of the handlers would pick up messages from the queues. In the RabbitMQ web console, I could see messages being delivered, but getting immediately nacked.

I tried to use the # as a message type (presuming a confusion with topic matching) AND I've tried to use the onUnhandled method. Still, I have been unable to handle messages.

Debugging further, I discovered that the messages on my queues do not have a type field specified. In the src/amqp/queue.js module, I see dispatch.publish( raw.type, raw, function( data ) { ... and raw.type was undefined.

Should the onUnhandled method be made capable of handling messages where the type header property is not defined? The property itself does not appear to be required by producers.

Thank you for the consideration!

@mxriverlynn
Copy link
Contributor

the message type is something that wascally adds on top of RabbitMQ. It is not part of the AMQP spec or the routing that happens with RabbitMQ exchanges and queue bindings. It's a feature that allows you to aggregate messages from any number of queues and have them go to the same handler, or allows you to take messages from one queue and have them go to any number of handlers. think of it like an extra layer of routing on top of RabbitMQ, but it only happens in your application code.

Consider a topology that has an exchange called "ex.1" and a queue called "q.1". You will need a binding between the exchange and the queue, so that messages can flow from the exchange to the queue. The binding may include a routing key, if you want.

when you publish a message to the exchange, you specify a routing key and a message type. the routing key ensures the message is delivered to the right queue. the message type ensures the right method in your code handles the message.

as an example:

var config = {
  connection: { ... },
  exchanges: [  { name: "ex.1", type: "direct" } ],
  queues: [ { name: "q.1", subscribe: true }  ],
  bindings: [ { exchange: "ex.1", target: "q.1" } ] // no routing key is set, so it is a "default" routing
};

function handleMessages(){
  // handle messages of a specific type
  wascally.handle("some.message.type", function(msg){
    console.log(msg.body);
    msg.ack();
  });
}

function publishMessage(){

  wascally.publish("ex.1", {
    routingKey: "", // blank, so the "default" (empty) routing is used,
    type: "some.message.type",
    body: {foo: "bar"}
  });

  wascally.publish("ex.1", {
    routingKey: "", // blank, so the "default" (empty) routing is used,
    type: "diff.msg.type",
    body: {foo: "baz"}
  });

}

wascally.configure(config)
  .then(handleMessages)
  .then(publishMessage)
  .then(function(){
    return wascally.closeAll()
  })
  .then(function(){
    process.exit();
  })

In this example (which may not run - i haven't actually tried to run it... consider this pseudo code example) there is a single queue and exchange bound with an empty (default) routing.

there are 2 messages published. both of them use an empty routing key, ensuring they will go to the same queue.

there is only one handle method. this method only handles some.message.type message types. since there is another message that is sent, but has a different message type, it will not be handled.

so, you have 2 messages going through the system. both of them go to the same queue and are picked up by wascally. but only one of them is handled by your handler method, because of the message type.

...

as a short-cut to get started, i would suggest keeping your routing key and message type the same - at least to get started. i found that to be the easiest thing to do, until i figured out what wascally was doing with the message type.

config = {
  bindings: [{ exchange: "ex.1", target: "q.1", keys: ["some.message.type"]})
}

wascally.publish("ex.1", {
  routingKey: "some.message.type",
  type: "some.message.type"
});

this way, there is a direct correlation between the routing of the message and the message type.

please note that you will run in to some limitations in doing this... you'll need more bindings in your exchanges and queues - one binding per "type" - but this makes it a little bit easier to get started, IME.

hope that helps!

@jhaugh42
Copy link
Author

It does, yes.

Granted my producer code (non-wascally) is not adhering to the conventions used in wascally. I can therefore address the behavior I've encountered by modifying my producer code to specify the type.

The documentation mentions this but might be a bit more clear about the convention, in the event others run into the same issue. Also, it may be beneficial to have some way of notifying consumers that, yes we are able to connect and read messages, but cannot dispatch them internally because the message type is undefined.

Thanks for the help and keep up the good work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants