payapi-rabbus
Version:
A micro-servicebus for RabbitMQ. Forked from https://github.com/derickbailey/rabbus.git solely to make it use payapi-whistlepunk as a dependency.
167 lines (116 loc) • 5 kB
Markdown
Rabbus message Producers and Consumers use a middleware system that allows you
to extend the capabilities of the bus. To use it, call the `.use` method of any
given message Consumer object (Receiver, Responder, Subscriber) or Producer
(Sender, Requester, Publisher).
The `use` method takes a callback function with a signature that varies depending
on whether you're using a producer or consumer.
## Consumer Middleware
The `use` method on consumers takes a callback with this signature:
```js
consumer.use(function(message, properties, actions, next){
});
```
The parameters are as follows:
* **message**: the message body
* **properties**: the properties of the message, including headers, etc.
* **actions**: an object containing various methods for interaction with the RabbitMQ message, and to continue the middleware chain
* **ack()**: the message is completely processed. acknowledge to the server. prevents any additional middleware from running
* **nack()**: the message cannot be processed, and should be re-queued for later. prevents any additional middleware from running
* **reject()**: the message cannot be processed and should not be re-queued. be sure you have a dead-letter queue before using this. prevents any additional middleware from running
* **reply(msg)**: send a reply back to the requester, during a request/response scenario. prevents any additional middleware from running
* **next()**: this middleware is done, and the next one can be called; call `next(err)` to forward an error to error handling middleware functions
As an example, you could log every message that gets sent through your consumer:
```js
var mySubscriber = new MySubscriber();
mySubscriber.use(function(message, properties, actions, next){
console.log("Got a message. Doing stuff with middleware.");
console.log(message);
// allow the middleware chain to continue
next();
});
```
In another scenario, you may want the middleware to `nack` the message because
some condition is not yet met.
```js
var rec = new SomeReceiver();
rec.use(function(message, properties, actions, next){
// check some conditions
if (message.someData && someOtherSystem.stuffNotReady()){
// conditions not met. nack the message and try again later
actions.nack();
} else {
// everything is good to go, allow the next middleware to run
next();
}
});
```
**WARNING:** If you forget to call `next()` or one of the other actions,
your message will be stuck in limbo, unacknowledged.
The `use` method on consumers takes a callback with this signature:
```js
producer.use(function(message, headers, next){
});
```
The parameters are as follows:
* **message**: the message body, which you can transform as needed
* **headers**: the headers of the message, which can be altered in any way you need
* **next()**: this middleware is done, and the next one can be called; call `next(err)` to forward an error to the error handlers
You can easily add / change headers or the actual message content in your
producer middleware. Any change you make to the `message` or `headers` objects
will make their way to the next middleware, and ultimately to RabbitMQ as part
of the message.
```js
var myPub = new MyPublisher();
myPub.use(function(message, headers, actions, next){
var hasFoo = !!(message.foo);
if (hasFoo){
// add data to the message body
message.bar = "foo is there";
message.baz = true;
}
// add a header to the message properties
headers.hasFoo = hasFoo;
// allow the middleware chain to continue
next();
});
```
**WARNING:** If you forget to call `next()` in your middleware,
the message will never be published. While this is generally dangerous, it can
be used to stop messages that should not be sent.
Whether you are using a Producer or Consumer, middleware is processed in the
order in which it was added: first in, first out.
For example, if you have a consumer that handles a message and then adds
some middleware, you will have the middleware processed first.
```js
responder.handle("message.type", function(msg, properties, actions, next){
console.log("handler fires last");
actions.ack();
});
responder.use(function(msg, props, actions, next){
console.log("first middleware");
next();
});
responder.use(function(msg, props, actions, next){
console.log("second middleware");
next();
});
responder.use(function(msg, props, actions, next){
console.log("third middleware");
next();
});
```
When this subscriber receives a message to handle, you will see the following:
```
first middleware
second middleware
third middleware
handler fires last
```
It is recommended you add the middleware before adding the `handle`
call. Adding middleware after calling `handle` could allow messages to be
handled before the middleware is in place.