Skip to content

Commit 2b46955

Browse files
Tom KirkpatrickTom Kirkpatrick
Tom Kirkpatrick
authored and
Tom Kirkpatrick
committed
feat: Switch from Jackrabbit to Rabbot
BREAKING CHANGE: Switch from Jackrabbit to Rabbot
1 parent 9fd422f commit 2b46955

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+854
-785
lines changed

.eslintignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/coverage/
22
node_modules/
3-
test/
3+
test/fixtures/test-server
4+
test/fixtures/test-server-acl

.eslintrc

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
{
22
"extends": "fullcube",
3-
"root": true,
4-
"rules": {
5-
"filenames/match-regex": 0
6-
}
3+
"root": true
74
}

README.md

+186-74
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,219 @@
11
# loopback-component-mq
2-
Loopback Component for working with a Message Queue
2+
Loopback Component for working with a Rabbit Message Queue.
33

44
[![Circle CI](https://circleci.com/gh/fullcube/loopback-component-mq.svg?style=svg)](https://circleci.com/gh/fullcube/loopback-component-mq) [![Dependencies](http://img.shields.io/david/fullcube/loopback-component-mq.svg?style=flat)](https://david-dm.org/fullcube/loopback-component-mq) [![Coverage Status](https://coveralls.io/repos/github/fullcube/loopback-component-mq/badge.svg?branch=master)](https://coveralls.io/github/fullcube/loopback-component-mq?branch=master)
55

6-
## Installation
6+
# Overview
7+
8+
This component provides a convenient way to work with RabbitMQ within a loopback application. This includes:
9+
10+
- Defining a RabbitMQ topology using the component-config.json
11+
- Registering message producers and consumers handlers using a mixin.
12+
- Inspecting RabbitMQ stats and queue statuses using a RabbitMQ loopback model.
13+
14+
Most of the functionality is enabled through the component configuration where you can define your RabbitMQ topology and configure access to the RabbitmQ stats.
15+
16+
In addition, an optional mixin is provided that provides an easy way to attach message producer and consumer helper methods directly to your loopback models.
17+
18+
# Installation
19+
20+
```
21+
npm install --save loopback-component-mq
22+
```
23+
24+
# Component Config
25+
26+
Create a `component-config.json` file in your server folder (if you don't already have one) and configure options inside `component-config.json`. *(see "Component Configuration"" section)*
27+
28+
```json
29+
"../node_modules/loopback-component-mq/lib": {
30+
"options": {
31+
"restPort": 15672,
32+
"acls": [{
33+
"accessType": "*",
34+
"principalType": "ROLE",
35+
"principalId": "$unauthenticated",
36+
"permission": "DENY"
37+
}],
38+
},
39+
"topology": {
40+
"connection": {
41+
"uri": "amqp://guest:[email protected]:5672/",
42+
},
43+
"exchanges": [{
44+
"name": "loopback-component-mq:item.write",
45+
"type": "topic",
46+
"persistent": true
47+
}],
48+
"queues": [{
49+
"name": "loopback-component-mq:client.item.write",
50+
"subscribe": true
51+
}],
52+
"bindings": [{
53+
"exchange": "loopback-component-mq:item.write",
54+
"target": "loopback-component-mq:client.item.write",
55+
"keys": ["#"]
56+
}]
57+
}
58+
}
59+
```
760

8-
1. Install in you loopback project:
61+
The 2 top-level keys are `options` and `topology` which are both objects.
962

10-
`npm install --save loopback-component-mq`
63+
## Options
1164

12-
2. Create a `component-config.json` file in your server folder (if you don't already have one)
65+
The `options` object has 2 keys:
1366

14-
3. Configure options inside `component-config.json`. *(see configuration section)*
67+
- `acls` (Array, optional), Define ACLs used to protect the RabbitMQ model that gets created.
1568

16-
```json
17-
{
18-
"loopback-component-mq": {
19-
"options": {
20-
"dataSource": "rabbit",
21-
"acls": [{
22-
"accessType": "*",
23-
"principalType": "ROLE",
24-
"principalId": "$unauthenticated",
25-
"permission": "DENY"
26-
}]
27-
},
28-
"topology": {
29-
"my-event-queue": {
30-
"consumer": {
31-
"model": "Event",
32-
"method": "consumeEventMessage"
33-
},
34-
"producer": {
35-
"model": "Event",
36-
"method": "produceEventMessage"
69+
- `restPort` (Number, optional, default: 15672), Define the rest port for your Rabbit management interface.
70+
71+
## Topology
72+
73+
In the `topology` object you configure the Rabbit connection, queues, exchanges, and bindings used by this component. Under the hood we use the [Rabbot](https://github.com/arobson/rabbot) package to establish a connection to and configure the topology for Rabbit.
74+
75+
See https://github.com/arobson/rabbot#configuration-via-json for details on how to configure your topology.
76+
77+
78+
# Mixin Config
79+
80+
Add the mixins property to your server/model-config.json:
81+
82+
```json
83+
{
84+
"_meta": {
85+
"sources": [
86+
"loopback/common/models",
87+
"loopback/server/models",
88+
"../common/models",
89+
"./models"
90+
],
91+
"mixins": [
92+
"loopback/common/mixins",
93+
"../node_modules/loopback-component-mq/lib/mixins",
94+
"../common/mixins"
95+
]
96+
}
97+
}
98+
```
99+
100+
To use with your Models add the mixins attribute to the definition object of your model config.
101+
102+
```json
103+
{
104+
"name": "Widget",
105+
"properties": {
106+
"name": {
107+
"type": "string",
108+
}
109+
},
110+
"mixins": {
111+
"MessageQueue": {
112+
"producers": {
113+
"publishItem": {
114+
"exchange": "item.write",
115+
"options": {
116+
"routingKey": "hi",
117+
"type": "company.project.messages.textMessage",
118+
"correlationId": "one",
119+
"contentType": "application/json",
120+
"messageId": "100",
121+
"expiresAfter": "1000 // TTL in ms, in this example 1 second",
122+
"timestamp": "// posix timestamp (long)",
123+
"mandatory": "true, //Must be set to true for onReturned to receive unqueued message",
124+
"headers": {
125+
"random": "application specific value"
126+
},
127+
"timeout": "// ms to wait before cancelling the publish and rejecting the promise"
37128
}
38129
}
130+
},
131+
"consumers": {
132+
"consumeItem": {
133+
"queue": "item.write",
134+
"type": "created"
135+
}
39136
}
40137
}
41138
}
42-
```
43-
44-
4. Configure the Rabbit Data Source inside `datasources.json`:
45-
46-
```json
47-
{
48-
"rabbit": {
49-
"name": "rabbit",
50-
"connector": "transient",
51-
"options": {
52-
"protocol": "amqp",
53-
"username": "guest",
54-
"password": "guest",
55-
"hostname": "localhost",
56-
"port": "5672",
57-
"restPort": "15672",
58-
"vhost": "/",
59-
"sslKey": ""
60-
}
61-
}
62-
}
63-
```
139+
}
140+
```
64141

65-
## Configuration
142+
The `MessageQueue` object has 2 keys:
66143

67-
The configuration of this component happens in `component-config.json`.
144+
- `producers` (Object, optional). Use this object to define message queue producer helper methods.
68145

69-
The 2 top-level keys are `options` and `topology` which are both objects.
146+
- `consumers` (Object, optional). Use this object to define message queue consumer helper methods.
70147

71-
### Options
148+
## Producers
72149

73-
The `options` object has 2 keys:
150+
You may use the mixin to define producer methods. These are essentially a wrapper around Rabbot's [`publish`](https://github.com/arobson/rabbot#publish-exchangename-options-connectionname-) method and provide a convenient way to publish messages to an exchange.
151+
152+
Producers accept 2 parameters:
153+
154+
- `exchange` (String, required) Name of the exchange to publish message to.
155+
- `options` (Object, optional) Default options passed to the Rabbot `publish` method.
156+
157+
Defining a `producer` will result in a static method being added to your Model using the key name as the method name. For example, the above configuration would create the static method `Widget.publishItem`. When called, a producer method will publish a message containing `payload` on the specified exchange, using the defined publishing options.
158+
159+
The method created accepts 2 parameters:
160+
161+
- `payload` (Any, required) The raw message that will be sent to the defined exchange.
162+
- `options` (String|Object, optional) If a string is provided, this will be used as the routing key for the message. You can also provide an options object, which allows you to override any of the default options passed to the Rabbot `publish` method.
163+
164+
## Consumers
165+
166+
You may use the mixin to define consumer methods which provide a convenient way to define a Rabbot message handler using Rabbot's [`handle`](https://github.com/arobson/rabbot#handle-options-handler-) method.
167+
168+
When defining a `consumer` on a queue, the component will register handler to consumer messages from the specified queue.
169+
170+
For example, the above configuration would register the static method `Widget.consumeItem` as a message handle for the `item.write` queue for messages that are using the `created` routing key.
171+
172+
Consumers accept 2 parameters:
173+
174+
- `queue` (String, required) Name of the queue to consumer messages from.
175+
- `type` (String, optional) Handle messages with this type name or pattern.
176+
177+
Having defined a consumer in your mixin, you are expected to define the actual consumer method on your model using the key name as the method name. For example, the above configuration would result in the static method `Widget.consumeItem` being registered as a message handler for messages with a type of `created`.
178+
179+
NOTE: you are responsible for creating the `Widget.consumeItem` method - which must accept 1 parameter:
180+
181+
- `payload` (Any, required) The raw message body pulled from the message queue.
182+
183+
To acknowledge (ack) the message your method should return a resolved Promise.
184+
185+
To reject (nack) the message your method should return a rejected Promise.
74186

75-
- `dataSource` (String, required). This is the name of the RabbitMQ datasource that is configured in `datasources.json`.
76-
Please note that this datasource does not use any `loopback-connector-*` packages, but just a way to tell the component
77-
how to connect to RabbitMQ.
187+
# Development
78188

79-
- `acls` (Array, optional). Use this array to configure the ACL's. This ACL protects the Queue model that gets created.
189+
Source files are located in the [`lib`] directory. Edit the source files to make changes while running `npm run dev` in the background.
80190

81-
### Topology
191+
```bash
192+
npm run dev
193+
```
82194

83-
In the `topology` object you configure the queues served by this component. The object key is the name of the Queue.
195+
Run with debugging output on:
84196

85-
Inside this queue definition you can define a `consumer`, a `producer`, or both. The `consumer` and `producer` objects
86-
both accept 2 properties, `model` and `method`.
197+
```bash
198+
DEBUG=loopback:component:mq* npm run dev
199+
```
87200

88-
#### Consumer
201+
# TESTING
89202

90-
When you defined a `consumer` on a queue, the component will call into the `Model.method()` defined when a new message
91-
arrives on the queue. The method will be called with 2 parameters, `payload` and `ack`. Payload is the raw message from
92-
the queue. The `ack` parameter is a message that is used to acknowledge to the queue that the message is being handled.
93-
Make sure to acknowledge all messages, because RabbitMQ won't allow any other messages to be picked up until the message
94-
is acknowledged, making the queue come to a halt.
203+
For error checking and to help maintain style this package uses `eslint` as a pretest.
95204

96-
#### Producer
205+
Run the tests in the `test` directory.
97206

98-
When defining a `producer` on a queue, the component will create the method `Model.method()` defined. The method created
99-
accepts 1 parameter, `payload`. The payload is the raw message that will be stored on the queue.
207+
```bash
208+
npm test
209+
```
100210

101-
## TODO
211+
Run with debugging output on:
102212

103-
- Add support for more types of Queues in the topology
213+
```bash
214+
DEBUG=loopback:component:mq* npm test
215+
```
104216

105-
## License
217+
# License
106218

107219
MIT

circle.yml

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ machine:
66
pre:
77
# Stop rabbitmq that comes with circle by default.
88
- sudo service rabbitmq-server stop
9+
environment:
10+
DEBUG: loopback:component:mq,rabbot*
911

1012
dependencies:
1113
pre:

0 commit comments

Comments
 (0)