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/.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
- # [3.2.0](https://github.com/benbria/node-amqp-connection-manager/compare/v3.1.1...v3.2.0) (2020-01-20)
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
- ### Features
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
- * add bindQueue and assertExchange on ChannelWrapper ([879e522](https://github.com/benbria/node-amqp-connection-manager/commit/879e522))
9
+ ### Bug Fixes
7
10
 
8
- ## [3.1.1](https://github.com/benbria/node-amqp-connection-manager/compare/v3.1.0...v3.1.1) (2020-01-06)
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
- * typo ([6055b02](https://github.com/benbria/node-amqp-connection-manager/commit/6055b02))
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
- # [3.1.0](https://github.com/benbria/node-amqp-connection-manager/compare/v3.0.0...v3.1.0) (2019-12-06)
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
- ### Features
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
- * Allow using URL object to connect, same format as amqplib accepts. ([f046680](https://github.com/benbria/node-amqp-connection-manager/commit/f046680))
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
- # [3.0.0](https://github.com/benbria/node-amqp-connection-manager/compare/v2.3.3...v3.0.0) (2019-07-04)
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
- ### Continuous Integration
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
- * Stop running tests for node 6 and node 8. ([164b882](https://github.com/benbria/node-amqp-connection-manager/commit/164b882))
34
+ ### Bug Fixes
28
35
 
36
+ - typo ([6055b02](https://github.com/jwalton/node-amqp-connection-manager/commit/6055b02))
29
37
 
30
- ### BREAKING CHANGES
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
- * Officially drop support for node 6 and node 8 (although they will probably still
33
- work).
40
+ ### Features
34
41
 
35
- ## [2.3.3](https://github.com/benbria/node-amqp-connection-manager/compare/v2.3.2...v2.3.3) (2019-06-25)
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
- ### Bug Fixes
46
+ ### Continuous Integration
39
47
 
40
- * **package:** update promise-breaker to version 5.0.0 ([ed91042](https://github.com/benbria/node-amqp-connection-manager/commit/ed91042))
48
+ - Stop running tests for node 6 and node 8. ([164b882](https://github.com/jwalton/node-amqp-connection-manager/commit/164b882))
41
49
 
42
- ## [2.3.2](https://github.com/benbria/node-amqp-connection-manager/compare/v2.3.1...v2.3.2) (2019-05-21)
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
- ### Bug Fixes
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
- * Null delta to get semantic-release to pick up [#65](https://github.com/benbria/node-amqp-connection-manager/issues/65). Fix [#84](https://github.com/benbria/node-amqp-connection-manager/issues/84). ([9737135](https://github.com/benbria/node-amqp-connection-manager/commit/9737135))
57
+ ### Bug Fixes
48
58
 
49
- ## [2.3.1](https://github.com/benbria/node-amqp-connection-manager/compare/v2.3.0...v2.3.1) (2019-04-01)
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
- * prevent too many connection attempts on error ([2760ce5](https://github.com/benbria/node-amqp-connection-manager/commit/2760ce5)), closes [#77](https://github.com/benbria/node-amqp-connection-manager/issues/77)
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
- # [2.3.0](https://github.com/benbria/node-amqp-connection-manager/compare/v2.2.0...v2.3.0) (2018-11-20)
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
- ### Features
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
- * Add ChannelWrapper.ackAll() and ChannelWrapper.nackAll(). ([0246695](https://github.com/benbria/node-amqp-connection-manager/commit/0246695)), closes [#60](https://github.com/benbria/node-amqp-connection-manager/issues/60)
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
- # [2.2.0](https://github.com/benbria/node-amqp-connection-manager/compare/v2.1.2...v2.2.0) (2018-09-25)
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
- ### Features
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
- * Set 'this' to be the channel wrapper in the setup function. ([551200f](https://github.com/benbria/node-amqp-connection-manager/commit/551200f))
81
+ ### Features
69
82
 
70
- ## [2.1.2](https://github.com/benbria/node-amqp-connection-manager/compare/v2.1.1...v2.1.2) (2018-09-13)
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
- * Export a default object from root module. ([78893c9](https://github.com/benbria/node-amqp-connection-manager/commit/78893c9)), closes [#51](https://github.com/benbria/node-amqp-connection-manager/issues/51)
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
- * Remove reconnection listener when closing the connection manager. ([eeb6e2b](https://github.com/benbria/node-amqp-connection-manager/commit/eeb6e2b))
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
- * Support for per URL connection options ([ec2d484](https://github.com/benbria/node-amqp-connection-manager/commit/ec2d484)), closes [#29](https://github.com/benbria/node-amqp-connection-manager/issues/29) [#34](https://github.com/benbria/node-amqp-connection-manager/issues/34) [#44](https://github.com/benbria/node-amqp-connection-manager/issues/44)
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
- * Rewrite all source in javascript. ([377d01d](https://github.com/benbria/node-amqp-connection-manager/commit/377d01d))
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
- * Officially dropping support for node v4.x.x.
113
+ - Officially dropping support for node v4.x.x.
103
114
 
104
115
  # 1.4.0
105
116
 
106
- * Add 'blocked' and 'unblocked' events (#25).
117
+ - Add 'blocked' and 'unblocked' events (#25).
107
118
 
108
119
  # 1.3.7
109
120
 
110
- * Fix bug where we would stop sending messages if remote gracefully closes connection.
121
+ - Fix bug where we would stop sending messages if remote gracefully closes connection.
111
122
 
112
123
  # 1.3.6
113
124
 
114
- * Fix bug where ChannelWrapper would expect setup function to return a Promise
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
- [![Build Status](https://travis-ci.org/benbria/node-amqp-connection-manager.svg?branch=master)](https://travis-ci.org/benbria/node-amqp-connection-manager)
2
- [![Coverage Status](https://coveralls.io/repos/benbria/node-amqp-connection-manager/badge.svg?branch=master&service=github)](https://coveralls.io/github/benbria/node-amqp-connection-manager?branch=master)
3
- [![Greenkeeper badge](https://badges.greenkeeper.io/benbria/node-amqp-connection-manager.svg)](https://greenkeeper.io/)
4
- [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
1
+ # amqp-connection-manager
5
2
 
6
- [![Dependency Status](https://david-dm.org/benbria/node-amqp-connection-manager.svg)](https://david-dm.org/benbria/node-amqp-connection-manager)
7
- [![devDependency Status](https://david-dm.org/benbria/node-amqp-connection-manager/dev-status.svg)](https://david-dm.org/benbria/node-amqp-connection-manager#info=devDependencies)
8
- [![peerDependency Status](https://david-dm.org/benbria/node-amqp-connection-manager/peer-status.svg)](https://david-dm.org/benbria/node-amqp-connection-manager#info=peerDependencies)
3
+ [![NPM version](https://badge.fury.io/js/amqp-connection-manager.svg)](https://npmjs.org/package/amqp-connection-manager)
4
+ ![Build Status](https://github.com/jwalton/node-amqp-connection-manager/workflows/GitHub%20CI/badge.svg)
5
+ [![Coverage Status](https://coveralls.io/repos/jwalton/node-amqp-connection-manager/badge.svg?branch=master&service=github)](https://coveralls.io/github/jwalton/node-amqp-connection-manager?branch=master)
6
+ [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
9
7
 
10
- Connection management for amqplib.
8
+ [![Dependency Status](https://david-dm.org/jwalton/node-amqp-connection-manager.svg)](https://david-dm.org/jwalton/node-amqp-connection-manager)
9
+ [![devDependency Status](https://david-dm.org/jwalton/node-amqp-connection-manager/dev-status.svg)](https://david-dm.org/jwalton/node-amqp-connection-manager#info=devDependencies)
10
+ [![peerDependency Status](https://david-dm.org/jwalton/node-amqp-connection-manager/peer-status.svg)](https://david-dm.org/jwalton/node-amqp-connection-manager#info=peerDependencies)
11
11
 
12
- # amqp-connection-manager
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
- * Automatically reconnect when your amqplib 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.
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
- npm install --save amqplib amqp-connection-manager
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. When you ask amqp-connection-manager for a
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
- json: true,
55
- setup: function(channel) {
56
- // `channel` here is a regular amqplib `ConfirmChannel`.
57
- // Note that `this` here is the channelWrapper instance.
58
- return channel.assertQueue('rxQueueName', {durable: true});
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.sendToQueue('rxQueueName', {hello: 'world'})
66
- .then(function() {
67
- return console.log("Message was sent! Hooray!");
68
- }).catch(function(err) {
69
- return console.log("Message was rejected... Boo!");
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. For example, suppose you
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. This can be done by adding a
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
- return Promise.all([
81
- channel.assertQueue("my-queue", { exclusive: true, autoDelete: true }),
82
- channel.bindQueue("my-queue", "my-exchange", "create"),
83
- channel.consume("my-queue", handleMessage)
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.) There is also a `removeSetup(setup, teardown)` which
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
- *must* either accept a callback or return a Promise.
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`. If a broker is
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
- * `options.heartbeatIntervalInSeconds` - Interval to send heartbeats to broker. Defaults to 5 seconds.
107
- * `options.reconnectTimeInSeconds` - The time to wait before trying to reconnect. If not specified,
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
- * `options.findServers(callback)` is a function which returns one or more servers to connect to. This should
110
- return either a single URL or an array of URLs. This is handy when you're using a service discovery mechanism
111
- such as Consul or etcd. Instead of taking a `callback`, this can also return a Promise. Note that if this
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
- * `options.connectionOptions` is passed as options to the amqplib connect method.
117
+ - `options.connectionOptions` is passed as options to the amqplib connect method.
114
118
 
115
119
  ### AmqpConnectionManager events
116
120
 
117
- * `connect({connection, url})` - Emitted whenever we successfully connect to a broker.
118
- * `disconnect({err})` - Emitted whenever we disconnect from a broker.
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. This is a proxy for the actual channel (which may or may not exist at any moment,
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
- * `options.name` - Name for this channel. Used for debugging.
128
- * `options.setup(channel, [cb])` - A function to call whenever we reconnect to the
129
- broker (and therefore create a new underlying channel.) This function should
130
- either accept a callback, or return a Promise. See `addSetup` below.
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
- * `options.json` if true, then ChannelWrapper assumes all messages passed to `publish()` and `sendToQueue()`
135
- are plain JSON objects. These will be encoded automatically before being sent.
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
- * `connect` - emitted every time this channel connects or reconnects.
148
- * `error(err, {name})` - emitted if an error occurs setting up the channel.
149
- * `close` - emitted when this channel closes via a call to `close()`
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. The `channel` object here is a ConfirmChannel from amqplib.
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. Note that in this case, if the setup throws an error, no 'error' event will
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. If the channel is currently connected, will call `teardown(channel)`, passing in the
171
- underlying amqplib ConfirmChannel. `teardown` should either take a callback or return a Promise.
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. The promise rejects if
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. They do nothing if the underlying
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("Must supply either `urls` or `findServers`");
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
- if (this._currentConnection) {
104
- this._currentConnection.removeAllListeners('close');
100
+ if (this._cancelRetriesHandler) {
101
+ this._cancelRetriesHandler();
105
102
 
106
- this._currentConnection.close();
107
- }
103
+ this._cancelRetriesHandler = null;
104
+ }
108
105
 
109
- this._currentConnection = null;
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._closed || this._connecting || this.isConnected()) {
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._connecting = true;
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 === "object") {
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).then(() => this._connect()) // `_connect()` should never throw.
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._connecting = false;
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; // TODO: Probably want to try right away here, especially if there are multiple brokers to try...
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
- return (0, _helpers.wait)(this.reconnectTimeInSeconds * 1000).then(() => {
205
- this._connecting = false;
206
- return this._connect();
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"}