amqp-connection-manager 3.2.0 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +8 -0
- package/.github/workflows/github-ci.yaml +50 -0
- package/.husky/pre-commit +2 -0
- package/.nyc_output/04c68bc0-350a-4b26-85f9-8270846392ff.json +1 -0
- package/.nyc_output/6c798ce9-a4b3-4959-9c25-92f7b331758f.json +1 -0
- package/.nyc_output/processinfo/04c68bc0-350a-4b26-85f9-8270846392ff.json +1 -0
- package/.nyc_output/processinfo/6c798ce9-a4b3-4959-9c25-92f7b331758f.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -1
- package/.prettierrc.js +27 -0
- package/CHANGELOG.md +54 -43
- package/README.md +67 -63
- package/lib/AmqpConnectionManager.js +38 -23
- package/lib/AmqpConnectionManager.js.map +1 -1
- package/lib/ChannelWrapper.js +60 -13
- package/lib/ChannelWrapper.js.map +1 -1
- package/lib/helpers.js +13 -3
- package/lib/helpers.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/package.json +78 -75
- package/.nyc_output/a7e3a119-2a8c-44cf-8209-927ee1d36caa.json +0 -1
- package/.nyc_output/c0823e86-c107-4a0a-8706-b14eb9b18f67.json +0 -1
- package/.nyc_output/f4ce670c-ed06-4884-9015-c86d83f0ea83.json +0 -1
- package/.nyc_output/processinfo/a7e3a119-2a8c-44cf-8209-927ee1d36caa.json +0 -1
- package/.nyc_output/processinfo/c0823e86-c107-4a0a-8706-b14eb9b18f67.json +0 -1
- package/.nyc_output/processinfo/f4ce670c-ed06-4884-9015-c86d83f0ea83.json +0 -1
- package/.travis.yml +0 -32
package/.prettierrc.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
trailingComma: 'es5',
|
|
3
|
+
printWidth: 100,
|
|
4
|
+
tabWidth: 4,
|
|
5
|
+
semi: true,
|
|
6
|
+
singleQuote: true,
|
|
7
|
+
overrides: [
|
|
8
|
+
{
|
|
9
|
+
files: '*.md',
|
|
10
|
+
options: {
|
|
11
|
+
tabWidth: 2,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
files: '*.yml',
|
|
16
|
+
options: {
|
|
17
|
+
tabWidth: 2,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
files: '*.yaml',
|
|
22
|
+
options: {
|
|
23
|
+
tabWidth: 2,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
};
|
package/CHANGELOG.md
CHANGED
|
@@ -1,115 +1,126 @@
|
|
|
1
|
-
|
|
1
|
+
## [3.2.4](https://github.com/jwalton/node-amqp-connection-manager/compare/v3.2.3...v3.2.4) (2021-08-23)
|
|
2
2
|
|
|
3
|
+
### Bug Fixes
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
- connection close not awaited ([8955fe7](https://github.com/jwalton/node-amqp-connection-manager/commit/8955fe7ee8f52505b629ee091f3658dfeb425c37))
|
|
6
|
+
|
|
7
|
+
## [3.2.3](https://github.com/jwalton/node-amqp-connection-manager/compare/v3.2.2...v3.2.3) (2021-08-21)
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
### Bug Fixes
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
- fixed issue with publish ignoring 'drain' event ([e195d9b](https://github.com/jwalton/node-amqp-connection-manager/commit/e195d9bc29907de49eec5e09aea3bba0b894d965)), closes [#129](https://github.com/jwalton/node-amqp-connection-manager/issues/129)
|
|
9
12
|
|
|
13
|
+
## [3.2.2](https://github.com/jwalton/node-amqp-connection-manager/compare/v3.2.1...v3.2.2) (2021-02-09)
|
|
10
14
|
|
|
11
15
|
### Bug Fixes
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
- When messages are acked/nacked, make sure we remove the correct message from the sent messages queue. ([c662026](https://github.com/jwalton/node-amqp-connection-manager/commit/c662026bc287e684a0f43ce2de7a44b80a88e8ff)), closes [#142](https://github.com/jwalton/node-amqp-connection-manager/issues/142)
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## [3.2.1](https://github.com/jwalton/node-amqp-connection-manager/compare/v3.2.0...v3.2.1) (2020-09-12)
|
|
16
20
|
|
|
21
|
+
### Bug Fixes
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
- Push never resolves if error occured (courtesy @SSANSH). ([48a78f8](https://github.com/jwalton/node-amqp-connection-manager/commit/48a78f8de5d39002035b37f27fc3e0ce5015490c))
|
|
24
|
+
- **package:** resolve hanging retry connection timeout by introducing cancelable timeout ([e37dd1a](https://github.com/jwalton/node-amqp-connection-manager/commit/e37dd1a4e423012910d31ae8bcebf781cac6f3b5))
|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
# [3.2.0](https://github.com/jwalton/node-amqp-connection-manager/compare/v3.1.1...v3.2.0) (2020-01-20)
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
### Features
|
|
23
29
|
|
|
30
|
+
- add bindQueue and assertExchange on ChannelWrapper ([879e522](https://github.com/jwalton/node-amqp-connection-manager/commit/879e522))
|
|
24
31
|
|
|
25
|
-
|
|
32
|
+
## [3.1.1](https://github.com/jwalton/node-amqp-connection-manager/compare/v3.1.0...v3.1.1) (2020-01-06)
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
### Bug Fixes
|
|
28
35
|
|
|
36
|
+
- typo ([6055b02](https://github.com/jwalton/node-amqp-connection-manager/commit/6055b02))
|
|
29
37
|
|
|
30
|
-
|
|
38
|
+
# [3.1.0](https://github.com/jwalton/node-amqp-connection-manager/compare/v3.0.0...v3.1.0) (2019-12-06)
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
work).
|
|
40
|
+
### Features
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
- Allow using URL object to connect, same format as amqplib accepts. ([f046680](https://github.com/jwalton/node-amqp-connection-manager/commit/f046680))
|
|
36
43
|
|
|
44
|
+
# [3.0.0](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.3.3...v3.0.0) (2019-07-04)
|
|
37
45
|
|
|
38
|
-
###
|
|
46
|
+
### Continuous Integration
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
- Stop running tests for node 6 and node 8. ([164b882](https://github.com/jwalton/node-amqp-connection-manager/commit/164b882))
|
|
41
49
|
|
|
42
|
-
|
|
50
|
+
### BREAKING CHANGES
|
|
43
51
|
|
|
52
|
+
- Officially drop support for node 6 and node 8 (although they will probably still
|
|
53
|
+
work).
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
## [2.3.3](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.3.2...v2.3.3) (2019-06-25)
|
|
46
56
|
|
|
47
|
-
|
|
57
|
+
### Bug Fixes
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
- **package:** update promise-breaker to version 5.0.0 ([ed91042](https://github.com/jwalton/node-amqp-connection-manager/commit/ed91042))
|
|
50
60
|
|
|
61
|
+
## [2.3.2](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.3.1...v2.3.2) (2019-05-21)
|
|
51
62
|
|
|
52
63
|
### Bug Fixes
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
- Null delta to get semantic-release to pick up [#65](https://github.com/jwalton/node-amqp-connection-manager/issues/65). Fix [#84](https://github.com/jwalton/node-amqp-connection-manager/issues/84). ([9737135](https://github.com/jwalton/node-amqp-connection-manager/commit/9737135))
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
## [2.3.1](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.3.0...v2.3.1) (2019-04-01)
|
|
57
68
|
|
|
69
|
+
### Bug Fixes
|
|
58
70
|
|
|
59
|
-
|
|
71
|
+
- prevent too many connection attempts on error ([2760ce5](https://github.com/jwalton/node-amqp-connection-manager/commit/2760ce5)), closes [#77](https://github.com/jwalton/node-amqp-connection-manager/issues/77)
|
|
60
72
|
|
|
61
|
-
|
|
73
|
+
# [2.3.0](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.2.0...v2.3.0) (2018-11-20)
|
|
62
74
|
|
|
63
|
-
|
|
75
|
+
### Features
|
|
64
76
|
|
|
77
|
+
- Add ChannelWrapper.ackAll() and ChannelWrapper.nackAll(). ([0246695](https://github.com/jwalton/node-amqp-connection-manager/commit/0246695)), closes [#60](https://github.com/jwalton/node-amqp-connection-manager/issues/60)
|
|
65
78
|
|
|
66
|
-
|
|
79
|
+
# [2.2.0](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.1.2...v2.2.0) (2018-09-25)
|
|
67
80
|
|
|
68
|
-
|
|
81
|
+
### Features
|
|
69
82
|
|
|
70
|
-
|
|
83
|
+
- Set 'this' to be the channel wrapper in the setup function. ([551200f](https://github.com/jwalton/node-amqp-connection-manager/commit/551200f))
|
|
71
84
|
|
|
85
|
+
## [2.1.2](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.1.1...v2.1.2) (2018-09-13)
|
|
72
86
|
|
|
73
87
|
### Bug Fixes
|
|
74
88
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
## [2.1.1](https://github.com/benbria/node-amqp-connection-manager/compare/v2.1.0...v2.1.1) (2018-09-05)
|
|
89
|
+
- Export a default object from root module. ([78893c9](https://github.com/jwalton/node-amqp-connection-manager/commit/78893c9)), closes [#51](https://github.com/jwalton/node-amqp-connection-manager/issues/51)
|
|
78
90
|
|
|
91
|
+
## [2.1.1](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.1.0...v2.1.1) (2018-09-05)
|
|
79
92
|
|
|
80
93
|
### Bug Fixes
|
|
81
94
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# [2.1.0](https://github.com/benbria/node-amqp-connection-manager/compare/v2.0.0...v2.1.0) (2018-08-09)
|
|
95
|
+
- Remove reconnection listener when closing the connection manager. ([eeb6e2b](https://github.com/jwalton/node-amqp-connection-manager/commit/eeb6e2b))
|
|
85
96
|
|
|
97
|
+
# [2.1.0](https://github.com/jwalton/node-amqp-connection-manager/compare/v2.0.0...v2.1.0) (2018-08-09)
|
|
86
98
|
|
|
87
99
|
### Features
|
|
88
100
|
|
|
89
|
-
|
|
101
|
+
- Support for per URL connection options ([ec2d484](https://github.com/jwalton/node-amqp-connection-manager/commit/ec2d484)), closes [#29](https://github.com/jwalton/node-amqp-connection-manager/issues/29) [#34](https://github.com/jwalton/node-amqp-connection-manager/issues/34) [#44](https://github.com/jwalton/node-amqp-connection-manager/issues/44)
|
|
90
102
|
|
|
91
103
|
<a name="2.0.0"></a>
|
|
92
|
-
# [2.0.0](https://github.com/benbria/node-amqp-connection-manager/compare/v1.4.2...v2.0.0) (2018-05-05)
|
|
93
104
|
|
|
105
|
+
# [2.0.0](https://github.com/jwalton/node-amqp-connection-manager/compare/v1.4.2...v2.0.0) (2018-05-05)
|
|
94
106
|
|
|
95
107
|
### Code Refactoring
|
|
96
108
|
|
|
97
|
-
|
|
98
|
-
|
|
109
|
+
- Rewrite all source in javascript. ([377d01d](https://github.com/jwalton/node-amqp-connection-manager/commit/377d01d))
|
|
99
110
|
|
|
100
111
|
### BREAKING CHANGES
|
|
101
112
|
|
|
102
|
-
|
|
113
|
+
- Officially dropping support for node v4.x.x.
|
|
103
114
|
|
|
104
115
|
# 1.4.0
|
|
105
116
|
|
|
106
|
-
|
|
117
|
+
- Add 'blocked' and 'unblocked' events (#25).
|
|
107
118
|
|
|
108
119
|
# 1.3.7
|
|
109
120
|
|
|
110
|
-
|
|
121
|
+
- Fix bug where we would stop sending messages if remote gracefully closes connection.
|
|
111
122
|
|
|
112
123
|
# 1.3.6
|
|
113
124
|
|
|
114
|
-
|
|
125
|
+
- Fix bug where ChannelWrapper would expect setup function to return a Promise
|
|
115
126
|
and not accept a callback if channel was already connected.
|
package/README.md
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
[](https://coveralls.io/github/benbria/node-amqp-connection-manager?branch=master)
|
|
3
|
-
[](https://greenkeeper.io/)
|
|
4
|
-
[](https://github.com/semantic-release/semantic-release)
|
|
1
|
+
# amqp-connection-manager
|
|
5
2
|
|
|
6
|
-
[](https://npmjs.org/package/amqp-connection-manager)
|
|
4
|
+

|
|
5
|
+
[](https://coveralls.io/github/jwalton/node-amqp-connection-manager?branch=master)
|
|
6
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
[](https://david-dm.org/jwalton/node-amqp-connection-manager)
|
|
9
|
+
[](https://david-dm.org/jwalton/node-amqp-connection-manager#info=devDependencies)
|
|
10
|
+
[](https://david-dm.org/jwalton/node-amqp-connection-manager#info=peerDependencies)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Connection management for amqplib. This is a wrapper around [amqplib](http://www.squaremobius.net/amqp.node/) which provides automatic reconnects.
|
|
13
13
|
|
|
14
14
|
## Features
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
- Automatically reconnect when your [amqplib](http://www.squaremobius.net/amqp.node/) broker dies in a fire.
|
|
17
|
+
- Round-robin connections between multiple brokers in a cluster.
|
|
18
|
+
- If messages are sent while the broker is unavailable, queues messages in memory until we reconnect.
|
|
19
|
+
- Supports both promises and callbacks (using [promise-breaker](https://github.com/jwalton/node-promise-breaker))
|
|
20
|
+
- Very un-opinionated library - a thin wrapper around [amqplib](http://www.squaremobius.net/amqp.node/).
|
|
21
21
|
|
|
22
22
|
## Installation
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
```sh
|
|
25
|
+
npm install --save amqplib amqp-connection-manager
|
|
26
|
+
```
|
|
25
27
|
|
|
26
28
|
## Basics
|
|
27
29
|
|
|
@@ -31,7 +33,7 @@ exist, or binding to queues), and then you send and receive messages and you
|
|
|
31
33
|
never touch that stuff again.
|
|
32
34
|
|
|
33
35
|
amqp-connection-manager will reconnect to a new broker whenever the broker it is
|
|
34
|
-
currently connected to dies.
|
|
36
|
+
currently connected to dies. When you ask amqp-connection-manager for a
|
|
35
37
|
channel, you specify one or more `setup` functions to run; the setup functions
|
|
36
38
|
will be run every time amqp-connection-manager reconnects, to make sure your
|
|
37
39
|
channel and broker are in a sane state.
|
|
@@ -51,46 +53,48 @@ var connection = amqp.connect(['amqp://localhost']);
|
|
|
51
53
|
// Ask the connection manager for a ChannelWrapper. Specify a setup function to
|
|
52
54
|
// run every time we reconnect to the broker.
|
|
53
55
|
var channelWrapper = connection.createChannel({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
json: true,
|
|
57
|
+
setup: function (channel) {
|
|
58
|
+
// `channel` here is a regular amqplib `ConfirmChannel`.
|
|
59
|
+
// Note that `this` here is the channelWrapper instance.
|
|
60
|
+
return channel.assertQueue('rxQueueName', { durable: true });
|
|
61
|
+
},
|
|
60
62
|
});
|
|
61
63
|
|
|
62
64
|
// Send some messages to the queue. If we're not currently connected, these will be queued up in memory
|
|
63
65
|
// until we connect. Note that `sendToQueue()` and `publish()` return a Promise which is fulfilled or rejected
|
|
64
66
|
// when the message is actually sent (or not sent.)
|
|
65
|
-
channelWrapper
|
|
66
|
-
.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
channelWrapper
|
|
68
|
+
.sendToQueue('rxQueueName', { hello: 'world' })
|
|
69
|
+
.then(function () {
|
|
70
|
+
return console.log('Message was sent! Hooray!');
|
|
71
|
+
})
|
|
72
|
+
.catch(function (err) {
|
|
73
|
+
return console.log('Message was rejected... Boo!');
|
|
74
|
+
});
|
|
71
75
|
```
|
|
72
76
|
|
|
73
|
-
Sometimes it's handy to modify a channel at run time.
|
|
77
|
+
Sometimes it's handy to modify a channel at run time. For example, suppose you
|
|
74
78
|
have a channel that's listening to one kind of message, and you decide you now
|
|
75
|
-
also want to listen to some other kind of message.
|
|
79
|
+
also want to listen to some other kind of message. This can be done by adding a
|
|
76
80
|
new setup function to an existing ChannelWrapper:
|
|
77
81
|
|
|
78
82
|
```js
|
|
79
|
-
channelWrapper.addSetup(function(channel) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
channelWrapper.addSetup(function (channel) {
|
|
84
|
+
return Promise.all([
|
|
85
|
+
channel.assertQueue('my-queue', { exclusive: true, autoDelete: true }),
|
|
86
|
+
channel.bindQueue('my-queue', 'my-exchange', 'create'),
|
|
87
|
+
channel.consume('my-queue', handleMessage),
|
|
88
|
+
]);
|
|
85
89
|
});
|
|
86
90
|
```
|
|
87
91
|
|
|
88
92
|
`addSetup()` returns a Promise which resolves when the setup function is
|
|
89
93
|
finished (or immediately, if the underlying connection is not currently
|
|
90
|
-
connected to a broker.)
|
|
94
|
+
connected to a broker.) There is also a `removeSetup(setup, teardown)` which
|
|
91
95
|
will run `teardown(channel)` if the channel is currently connected to a broker
|
|
92
96
|
(and will not run `teardown` at all otherwise.) Note that `setup` and `teardown`
|
|
93
|
-
|
|
97
|
+
_must_ either accept a callback or return a Promise.
|
|
94
98
|
|
|
95
99
|
See a complete example in the [examples](./examples) folder.
|
|
96
100
|
|
|
@@ -98,41 +102,41 @@ See a complete example in the [examples](./examples) folder.
|
|
|
98
102
|
|
|
99
103
|
### connect(urls, options)
|
|
100
104
|
|
|
101
|
-
Creates a new AmqpConnectionManager, which will connect to one of the URLs provided in `urls`.
|
|
105
|
+
Creates a new AmqpConnectionManager, which will connect to one of the URLs provided in `urls`. If a broker is
|
|
102
106
|
unreachable or dies, then AmqpConnectionManager will try the next available broker, round-robin.
|
|
103
107
|
|
|
104
108
|
Options:
|
|
105
109
|
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
- `options.heartbeatIntervalInSeconds` - Interval to send heartbeats to broker. Defaults to 5 seconds.
|
|
111
|
+
- `options.reconnectTimeInSeconds` - The time to wait before trying to reconnect. If not specified,
|
|
108
112
|
defaults to `heartbeatIntervalInSeconds`.
|
|
109
|
-
|
|
110
|
-
return either a single URL or an array of URLs.
|
|
111
|
-
such as Consul or etcd.
|
|
113
|
+
- `options.findServers(callback)` is a function which returns one or more servers to connect to. This should
|
|
114
|
+
return either a single URL or an array of URLs. This is handy when you're using a service discovery mechanism
|
|
115
|
+
such as Consul or etcd. Instead of taking a `callback`, this can also return a Promise. Note that if this
|
|
112
116
|
is supplied, then `urls` is ignored.
|
|
113
|
-
|
|
117
|
+
- `options.connectionOptions` is passed as options to the amqplib connect method.
|
|
114
118
|
|
|
115
119
|
### AmqpConnectionManager events
|
|
116
120
|
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
- `connect({connection, url})` - Emitted whenever we successfully connect to a broker.
|
|
122
|
+
- `disconnect({err})` - Emitted whenever we disconnect from a broker.
|
|
119
123
|
|
|
120
124
|
### AmqpConnectionManager#createChannel(options)
|
|
121
125
|
|
|
122
|
-
Create a new ChannelWrapper.
|
|
126
|
+
Create a new ChannelWrapper. This is a proxy for the actual channel (which may or may not exist at any moment,
|
|
123
127
|
depending on whether or not we are currently connected.)
|
|
124
128
|
|
|
125
129
|
Options:
|
|
126
130
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
broker (and therefore create a new underlying channel.)
|
|
130
|
-
either accept a callback, or return a Promise.
|
|
131
|
+
- `options.name` - Name for this channel. Used for debugging.
|
|
132
|
+
- `options.setup(channel, [cb])` - A function to call whenever we reconnect to the
|
|
133
|
+
broker (and therefore create a new underlying channel.) This function should
|
|
134
|
+
either accept a callback, or return a Promise. See `addSetup` below.
|
|
131
135
|
Note that `this` inside the setup function will the returned ChannelWrapper.
|
|
132
136
|
The ChannelWrapper has a special `context` member you can use to store
|
|
133
137
|
arbitrary data in.
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
- `options.json` if true, then ChannelWrapper assumes all messages passed to `publish()` and `sendToQueue()`
|
|
139
|
+
are plain JSON objects. These will be encoded automatically before being sent.
|
|
136
140
|
|
|
137
141
|
### AmqpConnectionManager#isConnected()
|
|
138
142
|
|
|
@@ -144,21 +148,21 @@ Close this AmqpConnectionManager and free all associated resources.
|
|
|
144
148
|
|
|
145
149
|
### ChannelWrapper events
|
|
146
150
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
- `connect` - emitted every time this channel connects or reconnects.
|
|
152
|
+
- `error(err, {name})` - emitted if an error occurs setting up the channel.
|
|
153
|
+
- `close` - emitted when this channel closes via a call to `close()`
|
|
150
154
|
|
|
151
155
|
### ChannelWrapper#addSetup(setup)
|
|
152
156
|
|
|
153
157
|
Adds a new 'setup handler'.
|
|
154
158
|
|
|
155
159
|
`setup(channel, [cb])` is a function to call when a new underlying channel is created - handy for asserting
|
|
156
|
-
exchanges and queues exists, and whatnot.
|
|
160
|
+
exchanges and queues exists, and whatnot. The `channel` object here is a ConfirmChannel from amqplib.
|
|
157
161
|
The `setup` function should return a Promise (or optionally take a callback) - no messages will be sent until
|
|
158
162
|
this Promise resolves.
|
|
159
163
|
|
|
160
164
|
If there is a connection, `setup()` will be run immediately, and the addSetup Promise/callback won't resolve
|
|
161
|
-
until `setup` is complete.
|
|
165
|
+
until `setup` is complete. Note that in this case, if the setup throws an error, no 'error' event will
|
|
162
166
|
be emitted, since you can just handle the error here (although the `setup` will still be added for future
|
|
163
167
|
reconnects, even if it throws an error.)
|
|
164
168
|
|
|
@@ -167,19 +171,19 @@ event.
|
|
|
167
171
|
|
|
168
172
|
### ChannelWrapper#removeSetup(setup, teardown)
|
|
169
173
|
|
|
170
|
-
Removes a setup handler.
|
|
171
|
-
underlying amqplib ConfirmChannel.
|
|
174
|
+
Removes a setup handler. If the channel is currently connected, will call `teardown(channel)`, passing in the
|
|
175
|
+
underlying amqplib ConfirmChannel. `teardown` should either take a callback or return a Promise.
|
|
172
176
|
|
|
173
177
|
### ChannelWrapper#publish and ChannelWrapper#sendToQueue
|
|
174
178
|
|
|
175
179
|
These work exactly like their counterparts in amqplib's Channel, except that they return a Promise (or accept a
|
|
176
|
-
callback) which resolves when the message is confirmed to have been delivered to the broker.
|
|
180
|
+
callback) which resolves when the message is confirmed to have been delivered to the broker. The promise rejects if
|
|
177
181
|
either the broker refuses the message, or if `close()` is called on the ChannelWrapper before the message can be
|
|
178
182
|
delivered.
|
|
179
183
|
|
|
180
184
|
### ChannelWrapper#ack and ChannelWrapper#nack
|
|
181
185
|
|
|
182
|
-
These are just aliases for calling `ack()` and `nack()` on the underlying channel.
|
|
186
|
+
These are just aliases for calling `ack()` and `nack()` on the underlying channel. They do nothing if the underlying
|
|
183
187
|
channel is not connected.
|
|
184
188
|
|
|
185
189
|
### ChannelWrapper#queueLength()
|
|
@@ -62,7 +62,7 @@ class AmqpConnectionManager extends _events.EventEmitter {
|
|
|
62
62
|
super();
|
|
63
63
|
|
|
64
64
|
if (!urls && !options.findServers) {
|
|
65
|
-
throw new Error(
|
|
65
|
+
throw new Error('Must supply either `urls` or `findServers`');
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
this._channels = [];
|
|
@@ -96,17 +96,28 @@ class AmqpConnectionManager extends _events.EventEmitter {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
this._closed = true;
|
|
99
|
-
return Promise.all(this._channels.map(channel => channel.close())).catch(function () {// Ignore errors closing channels.
|
|
100
|
-
}).then(() => {
|
|
101
|
-
this._channels = [];
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
if (this._cancelRetriesHandler) {
|
|
101
|
+
this._cancelRetriesHandler();
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
this._cancelRetriesHandler = null;
|
|
104
|
+
}
|
|
108
105
|
|
|
109
|
-
|
|
106
|
+
return Promise.resolve(this._connectPromise).then(() => {
|
|
107
|
+
return Promise.all(this._channels.map(channel => channel.close())).catch(function () {// Ignore errors closing channels.
|
|
108
|
+
}).then(() => {
|
|
109
|
+
this._channels = [];
|
|
110
|
+
|
|
111
|
+
if (this._currentConnection) {
|
|
112
|
+
this._currentConnection.removeAllListeners('close');
|
|
113
|
+
|
|
114
|
+
return this._currentConnection.close();
|
|
115
|
+
} else {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}).then(() => {
|
|
119
|
+
this._currentConnection = null;
|
|
120
|
+
});
|
|
110
121
|
});
|
|
111
122
|
}
|
|
112
123
|
|
|
@@ -115,12 +126,15 @@ class AmqpConnectionManager extends _events.EventEmitter {
|
|
|
115
126
|
}
|
|
116
127
|
|
|
117
128
|
_connect() {
|
|
118
|
-
if (this.
|
|
129
|
+
if (this._connectPromise) {
|
|
130
|
+
return this._connectPromise;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (this._closed || this.isConnected()) {
|
|
119
134
|
return Promise.resolve();
|
|
120
135
|
}
|
|
121
136
|
|
|
122
|
-
this.
|
|
123
|
-
return Promise.resolve().then(() => {
|
|
137
|
+
this._connectPromise = Promise.resolve().then(() => {
|
|
124
138
|
if (!this._urls || this._currentUrl >= this._urls.length) {
|
|
125
139
|
this._currentUrl = 0;
|
|
126
140
|
return _promiseBreaker.default.callFn(this._findServers, 0, null);
|
|
@@ -146,7 +160,7 @@ class AmqpConnectionManager extends _events.EventEmitter {
|
|
|
146
160
|
const connectionOptions = url.connectionOptions || this.connectionOptions;
|
|
147
161
|
let amqpUrl = null;
|
|
148
162
|
|
|
149
|
-
if (typeof urlString ===
|
|
163
|
+
if (typeof urlString === 'object') {
|
|
150
164
|
amqpUrl = Object.assign({}, url);
|
|
151
165
|
|
|
152
166
|
if (!amqpUrl.heartbeat) {
|
|
@@ -171,9 +185,7 @@ class AmqpConnectionManager extends _events.EventEmitter {
|
|
|
171
185
|
reason
|
|
172
186
|
}));
|
|
173
187
|
connection.on('unblocked', () => this.emit('unblocked'));
|
|
174
|
-
connection.on('error', () =>
|
|
175
|
-
/* err */
|
|
176
|
-
{// if this event was emitted, then the connection was already closed,
|
|
188
|
+
connection.on('error', () => {// if this event was emitted, then the connection was already closed,
|
|
177
189
|
// so no need to call #close here
|
|
178
190
|
// also, 'close' is emitted after 'error',
|
|
179
191
|
// so no need for work already done in 'close' handler
|
|
@@ -184,10 +196,12 @@ class AmqpConnectionManager extends _events.EventEmitter {
|
|
|
184
196
|
this.emit('disconnect', {
|
|
185
197
|
err
|
|
186
198
|
});
|
|
187
|
-
(0, _helpers.wait)(this.reconnectTimeInSeconds * 1000)
|
|
199
|
+
const handle = (0, _helpers.wait)(this.reconnectTimeInSeconds * 1000);
|
|
200
|
+
this._cancelRetriesHandler = handle.cancel;
|
|
201
|
+
handle.promise().then(() => this._connect()) // `_connect()` should never throw.
|
|
188
202
|
.catch(neverThrows);
|
|
189
203
|
});
|
|
190
|
-
this.
|
|
204
|
+
this._connectPromise = null;
|
|
191
205
|
this.emit('connect', {
|
|
192
206
|
connection,
|
|
193
207
|
url: urlString
|
|
@@ -199,13 +213,14 @@ class AmqpConnectionManager extends _events.EventEmitter {
|
|
|
199
213
|
err
|
|
200
214
|
}); // Connection failed...
|
|
201
215
|
|
|
202
|
-
this._currentConnection = null;
|
|
216
|
+
this._currentConnection = null;
|
|
217
|
+
this._connectPromise = null; // TODO: Probably want to try right away here, especially if there are multiple brokers to try...
|
|
203
218
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
});
|
|
219
|
+
const handle = (0, _helpers.wait)(this.reconnectTimeInSeconds * 1000);
|
|
220
|
+
this._cancelRetriesHandler = handle.cancel;
|
|
221
|
+
return handle.promise().then(() => this._connect());
|
|
208
222
|
});
|
|
223
|
+
return this._connectPromise;
|
|
209
224
|
}
|
|
210
225
|
|
|
211
226
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/AmqpConnectionManager.js"],"names":["HEARTBEAT_IN_SECONDS","neverThrows","err","setImmediate","Error","message","stack","AmqpConnectionManager","EventEmitter","constructor","urls","options","findServers","_channels","_currentUrl","connectionOptions","heartbeatIntervalInSeconds","reconnectTimeInSeconds","setMaxListeners","_findServers","Promise","resolve","_connect","createChannel","channel","ChannelWrapper","push","once","filter","c","close","_closed","all","map","catch","then","_currentConnection","removeAllListeners","isConnected","_connecting","_urls","length","pb","callFn","Array","isArray","url","urlString","amqpUrl","Object","assign","heartbeat","urlUtils","parse","search","format","amqp","connect","connection","on","reason","emit"],"mappings":"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","sourcesContent":["import { EventEmitter } from 'events';\nimport amqp from 'amqplib';\nimport urlUtils from 'url';\n\nimport ChannelWrapper from './ChannelWrapper';\nimport { wait } from './helpers';\nimport pb from 'promise-breaker';\n\n// Default heartbeat time.\nconst HEARTBEAT_IN_SECONDS = 5;\n\n/* istanbul ignore next */\nfunction neverThrows() {\n return err =>\n setImmediate(() => {\n throw new Error(`AmqpConnectionManager - should never get here: ${err.message}\\n` +\n err.stack);\n });\n}\n\n//\n// Events:\n// * `connect({connection, url})` - Emitted whenever we connect to a broker.\n// * `disconnect({err})` - Emitted whenever we disconnect from a broker.\n//\nexport default class AmqpConnectionManager extends EventEmitter {\n /**\n * Create a new AmqplibConnectionManager.\n *\n * @param {(string|Object)[]} urls - An array of brokers to connect to.\n * Takes url strings or objects {url: string, connectionOptions?: object}\n * If present, a broker's [connectionOptions] will be used instead\n * of [options.connectionOptions] when passed to the amqplib connect method.\n * AmqplibConnectionManager will round-robin between them whenever it\n * needs to create a new connection.\n * @param {Object} [options={}] -\n * @param {number} [options.heartbeatIntervalInSeconds=5] - The interval,\n * in seconds, to send heartbeats.\n * @param {number} [options.reconnectTimeInSeconds] - The time to wait\n * before trying to reconnect. If not specified, defaults to\n * `heartbeatIntervalInSeconds`.\n * @param {Object} [options.connectionOptions] - Passed to the amqplib\n * connect method.\n * @param {function} [options.findServers] - A `fn(callback)` or a `fn()`\n * which returns a Promise. This should resolve to one or more servers\n * to connect to, either a single URL or an array of URLs. This is handy\n * when you're using a service discovery mechanism such as Consul or etcd.\n * Note that if this is supplied, then `urls` is ignored.\n */\n constructor(urls, options = {}) {\n super();\n if(!urls && !options.findServers) {\n throw new Error(\"Must supply either `urls` or `findServers`\");\n }\n this._channels = [];\n\n this._currentUrl = 0;\n this.connectionOptions = options.connectionOptions;\n\n this.heartbeatIntervalInSeconds = options.heartbeatIntervalInSeconds || HEARTBEAT_IN_SECONDS;\n this.reconnectTimeInSeconds = options.reconnectTimeInSeconds || this.heartbeatIntervalInSeconds;\n\n // There will be one listener per channel, and there could be a lot of channels, so disable warnings from node.\n this.setMaxListeners(0);\n\n this._findServers = options.findServers || (() => Promise.resolve(urls));\n\n this._connect();\n }\n\n // `options` here are any options that can be passed to ChannelWrapper.\n createChannel(options = {}) {\n const channel = new ChannelWrapper(this, options);\n this._channels.push(channel);\n channel.once('close', () => {\n this._channels = this._channels.filter(c => c !== channel);\n });\n return channel;\n }\n\n close() {\n if(this._closed) { return Promise.resolve(); }\n this._closed = true;\n\n return Promise.all(this._channels.map(channel => channel.close()))\n .catch(function() {\n // Ignore errors closing channels.\n })\n .then(() => {\n this._channels = [];\n if(this._currentConnection) {\n this._currentConnection.removeAllListeners('close');\n this._currentConnection.close();\n }\n this._currentConnection = null;\n });\n }\n\n isConnected() {\n return !!this._currentConnection;\n }\n\n _connect() {\n if(this._closed || this._connecting || this.isConnected()) {\n return Promise.resolve();\n }\n\n this._connecting = true;\n\n return Promise.resolve()\n .then(() => {\n if(!this._urls || (this._currentUrl >= this._urls.length)) {\n this._currentUrl = 0;\n return pb.callFn(this._findServers, 0, null);\n } else {\n return this._urls;\n }\n })\n .then(urls => {\n if(urls && !Array.isArray(urls)) { urls = [urls]; }\n this._urls = urls;\n\n if(!urls || (urls.length === 0)) {\n throw new Error('amqp-connection-manager: No servers found');\n }\n\n // Round robin between brokers\n const url = urls[this._currentUrl];\n this._currentUrl++;\n\n // url can be a string or object {url: string, connectionOptions?: object}\n const urlString = url.url || url;\n const connectionOptions = url.connectionOptions || this.connectionOptions;\n\n let amqpUrl = null;\n\n if(typeof urlString === \"object\") {\n amqpUrl = Object.assign({}, url);\n if(!amqpUrl.heartbeat) {\n amqpUrl.heartbeat = this.heartbeatIntervalInSeconds;\n }\n }else {\n amqpUrl = urlUtils.parse(urlString);\n if(amqpUrl.search) {\n amqpUrl.search += `&heartbeat=${this.heartbeatIntervalInSeconds}`;\n } else {\n amqpUrl.search = `?heartbeat=${this.heartbeatIntervalInSeconds}`;\n }\n amqpUrl = urlUtils.format(amqpUrl);\n }\n\n\n return amqp.connect(amqpUrl, connectionOptions)\n .then(connection => {\n this._currentConnection = connection;\n\n //emit 'blocked' when RabbitMQ server decides to block the connection (resources running low)\n connection.on('blocked', reason => this.emit('blocked', { reason }));\n\n connection.on('unblocked', () => this.emit('unblocked'));\n\n connection.on('error', (/* err */) => {\n // if this event was emitted, then the connection was already closed,\n // so no need to call #close here\n // also, 'close' is emitted after 'error',\n // so no need for work already done in 'close' handler\n });\n\n // Reconnect if the connection closes\n connection.on('close', err => {\n this._currentConnection = null;\n this.emit('disconnect', { err });\n\n wait(this.reconnectTimeInSeconds * 1000)\n .then(() => this._connect())\n // `_connect()` should never throw.\n .catch(neverThrows);\n });\n\n this._connecting = false;\n this.emit('connect', { connection, url: urlString });\n\n return null;\n });\n })\n .catch(err => {\n this.emit('disconnect', { err });\n\n // Connection failed...\n this._currentConnection = null;\n\n // TODO: Probably want to try right away here, especially if there are multiple brokers to try...\n return wait(this.reconnectTimeInSeconds * 1000)\n .then(() => {\n this._connecting = false;\n return this._connect();\n });\n });\n }\n}\n"],"file":"AmqpConnectionManager.js"}
|
|
1
|
+
{"version":3,"sources":["../src/AmqpConnectionManager.js"],"names":["HEARTBEAT_IN_SECONDS","neverThrows","err","setImmediate","Error","message","stack","AmqpConnectionManager","EventEmitter","constructor","urls","options","findServers","_channels","_currentUrl","connectionOptions","heartbeatIntervalInSeconds","reconnectTimeInSeconds","setMaxListeners","_findServers","Promise","resolve","_connect","createChannel","channel","ChannelWrapper","push","once","filter","c","close","_closed","_cancelRetriesHandler","_connectPromise","then","all","map","catch","_currentConnection","removeAllListeners","isConnected","_urls","length","pb","callFn","Array","isArray","url","urlString","amqpUrl","Object","assign","heartbeat","urlUtils","parse","search","format","amqp","connect","connection","on","reason","emit","handle","cancel","promise"],"mappings":"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","sourcesContent":["import { EventEmitter } from 'events';\nimport amqp from 'amqplib';\nimport urlUtils from 'url';\n\nimport ChannelWrapper from './ChannelWrapper';\nimport { wait } from './helpers';\nimport pb from 'promise-breaker';\n\n// Default heartbeat time.\nconst HEARTBEAT_IN_SECONDS = 5;\n\n/* istanbul ignore next */\nfunction neverThrows() {\n return (err) =>\n setImmediate(() => {\n throw new Error(\n `AmqpConnectionManager - should never get here: ${err.message}\\n` + err.stack\n );\n });\n}\n\n//\n// Events:\n// * `connect({connection, url})` - Emitted whenever we connect to a broker.\n// * `disconnect({err})` - Emitted whenever we disconnect from a broker.\n//\nexport default class AmqpConnectionManager extends EventEmitter {\n /**\n * Create a new AmqplibConnectionManager.\n *\n * @param {(string|Object)[]} urls - An array of brokers to connect to.\n * Takes url strings or objects {url: string, connectionOptions?: object}\n * If present, a broker's [connectionOptions] will be used instead\n * of [options.connectionOptions] when passed to the amqplib connect method.\n * AmqplibConnectionManager will round-robin between them whenever it\n * needs to create a new connection.\n * @param {Object} [options={}] -\n * @param {number} [options.heartbeatIntervalInSeconds=5] - The interval,\n * in seconds, to send heartbeats.\n * @param {number} [options.reconnectTimeInSeconds] - The time to wait\n * before trying to reconnect. If not specified, defaults to\n * `heartbeatIntervalInSeconds`.\n * @param {Object} [options.connectionOptions] - Passed to the amqplib\n * connect method.\n * @param {function} [options.findServers] - A `fn(callback)` or a `fn()`\n * which returns a Promise. This should resolve to one or more servers\n * to connect to, either a single URL or an array of URLs. This is handy\n * when you're using a service discovery mechanism such as Consul or etcd.\n * Note that if this is supplied, then `urls` is ignored.\n */\n constructor(urls, options = {}) {\n super();\n if (!urls && !options.findServers) {\n throw new Error('Must supply either `urls` or `findServers`');\n }\n this._channels = [];\n\n this._currentUrl = 0;\n this.connectionOptions = options.connectionOptions;\n\n this.heartbeatIntervalInSeconds =\n options.heartbeatIntervalInSeconds || HEARTBEAT_IN_SECONDS;\n this.reconnectTimeInSeconds =\n options.reconnectTimeInSeconds || this.heartbeatIntervalInSeconds;\n\n // There will be one listener per channel, and there could be a lot of channels, so disable warnings from node.\n this.setMaxListeners(0);\n\n this._findServers = options.findServers || (() => Promise.resolve(urls));\n\n this._connect();\n }\n\n // `options` here are any options that can be passed to ChannelWrapper.\n createChannel(options = {}) {\n const channel = new ChannelWrapper(this, options);\n this._channels.push(channel);\n channel.once('close', () => {\n this._channels = this._channels.filter((c) => c !== channel);\n });\n return channel;\n }\n\n close() {\n if (this._closed) {\n return Promise.resolve();\n }\n this._closed = true;\n\n if (this._cancelRetriesHandler) {\n this._cancelRetriesHandler();\n this._cancelRetriesHandler = null;\n }\n\n return Promise.resolve(this._connectPromise).then(() => {\n return Promise.all(this._channels.map((channel) => channel.close()))\n .catch(function () {\n // Ignore errors closing channels.\n })\n .then(() => {\n this._channels = [];\n if (this._currentConnection) {\n this._currentConnection.removeAllListeners('close');\n return this._currentConnection.close();\n } else {\n return null;\n }\n })\n .then(() => {\n this._currentConnection = null;\n });\n });\n }\n\n isConnected() {\n return !!this._currentConnection;\n }\n\n _connect() {\n if (this._connectPromise) {\n return this._connectPromise;\n }\n\n if (this._closed || this.isConnected()) {\n return Promise.resolve();\n }\n\n this._connectPromise = Promise.resolve()\n .then(() => {\n if (!this._urls || this._currentUrl >= this._urls.length) {\n this._currentUrl = 0;\n return pb.callFn(this._findServers, 0, null);\n } else {\n return this._urls;\n }\n })\n .then((urls) => {\n if (urls && !Array.isArray(urls)) {\n urls = [urls];\n }\n this._urls = urls;\n\n if (!urls || urls.length === 0) {\n throw new Error('amqp-connection-manager: No servers found');\n }\n\n // Round robin between brokers\n const url = urls[this._currentUrl];\n this._currentUrl++;\n\n // url can be a string or object {url: string, connectionOptions?: object}\n const urlString = url.url || url;\n const connectionOptions = url.connectionOptions || this.connectionOptions;\n\n let amqpUrl = null;\n\n if (typeof urlString === 'object') {\n amqpUrl = Object.assign({}, url);\n if (!amqpUrl.heartbeat) {\n amqpUrl.heartbeat = this.heartbeatIntervalInSeconds;\n }\n } else {\n amqpUrl = urlUtils.parse(urlString);\n if (amqpUrl.search) {\n amqpUrl.search += `&heartbeat=${this.heartbeatIntervalInSeconds}`;\n } else {\n amqpUrl.search = `?heartbeat=${this.heartbeatIntervalInSeconds}`;\n }\n amqpUrl = urlUtils.format(amqpUrl);\n }\n\n return amqp.connect(amqpUrl, connectionOptions).then((connection) => {\n this._currentConnection = connection;\n\n //emit 'blocked' when RabbitMQ server decides to block the connection (resources running low)\n connection.on('blocked', (reason) => this.emit('blocked', { reason }));\n\n connection.on('unblocked', () => this.emit('unblocked'));\n\n connection.on('error', (/* err */) => {\n // if this event was emitted, then the connection was already closed,\n // so no need to call #close here\n // also, 'close' is emitted after 'error',\n // so no need for work already done in 'close' handler\n });\n\n // Reconnect if the connection closes\n connection.on('close', (err) => {\n this._currentConnection = null;\n this.emit('disconnect', { err });\n\n const handle = wait(this.reconnectTimeInSeconds * 1000);\n this._cancelRetriesHandler = handle.cancel;\n\n handle\n .promise()\n .then(() => this._connect())\n // `_connect()` should never throw.\n .catch(neverThrows);\n });\n\n this._connectPromise = null;\n this.emit('connect', { connection, url: urlString });\n\n return null;\n });\n })\n .catch((err) => {\n this.emit('disconnect', { err });\n\n // Connection failed...\n this._currentConnection = null;\n this._connectPromise = null;\n\n // TODO: Probably want to try right away here, especially if there are multiple brokers to try...\n const handle = wait(this.reconnectTimeInSeconds * 1000);\n this._cancelRetriesHandler = handle.cancel;\n\n return handle.promise().then(() => this._connect());\n });\n\n return this._connectPromise;\n }\n}\n"],"file":"AmqpConnectionManager.js"}
|