rascal 9.1.2 → 9.4.0

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/.snyk ADDED
@@ -0,0 +1,8 @@
1
+ # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
2
+ version: v1.13.5
3
+ ignore: {}
4
+ # patches apply the minimum changes required to fix a vulnerability
5
+ patch:
6
+ SNYK-JS-LODASH-567746:
7
+ - lodash:
8
+ patched: '2020-05-02T09:49:46.494Z'
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.4.0
4
+ ### Added
5
+ - vhost_initialised event
6
+ - publication paused notifications
7
+ - publication.abort
8
+
9
+ ### Updated
10
+ - broker error events now include vhost connection details
11
+
12
+ ## 9.3.0
13
+ ### Updated
14
+ - [Fixed #78](https://github.com/guidesmiths/rascal/issues/78) by using a baseline config, and only laying connection options via withDefaultConfig
15
+
16
+ ## 9.2.0
17
+ ### Added
18
+ - [Fixed #93](https://github.com/guidesmiths/rascal/issues/93) through use of setInterval to keep node process active in the event of broker restart.
19
+
20
+ ### Updated
21
+ - Dependencies
22
+ - Patched lodash
23
+ - Added snyk
24
+
25
+ ## 9.1.3
26
+ ### Updated
27
+ - Fixed bug where channels were destroyed instead of returned to the pool
28
+
3
29
  ## 9.1.2
4
30
  ### Updated
5
31
  - Test to see whether setTimeout.unref is available before calling it
package/README.md CHANGED
@@ -114,8 +114,8 @@ The reason Rascal nacks the message is because the alternative is to rollback an
114
114
  1. Immediately after obtaining a broker instance
115
115
 
116
116
  ```js
117
- broker.on('error', (err) => {
118
- console.error('Broker error', err)
117
+ broker.on('error', (err, { vhost, connectionUrl }) => {
118
+ console.error('Broker error', err, vhost, connectionUrl)
119
119
  })
120
120
  ```
121
121
 
@@ -195,6 +195,28 @@ The reason Rascal nacks the message is because the alternative is to rollback an
195
195
  })
196
196
  ```
197
197
 
198
+ ### Other Broker Events
199
+
200
+ #### vhost_initialised
201
+ The broker emits the `vhost_initialised` event after recovering from a connection error. An object containing the vhost name and connection url (with obfuscated password) are passed to he event handler. e.g.
202
+
203
+ ```js
204
+ broker.on('vhost_initialised', ({ vhost, connectionUrl }) => {
205
+ console.log(`Vhost: ${vhost} was initialised using connection: ${connectionUrl}`);
206
+ })
207
+ ```
208
+
209
+ #### blocked / unblocked
210
+ RabbitMQ notifies clients of [blocked and unblocked](https://www.rabbitmq.com/connection-blocked.html) connections, which rascal forwards from the connection to the broker. e.g.
211
+ ```js
212
+ broker.on('blocked', (reason, { vhost, connectionUrl }) => {
213
+ console.log(`Vhost: ${vhost} was blocked using connection: ${connectionUrl}. Reason: ${reason}`);
214
+ })
215
+ broker.on('unblocked', ({ vhost, connectionUrl }) => {
216
+ console.log(`Vhost: ${vhost} was unblocked using connection: ${connectionUrl}.`);
217
+ })
218
+ ```
219
+
198
220
  ## Configuration
199
221
  Rascal is highly configurable, but ships with what we consider to be sensible defaults (optimised for reliability rather than speed) for production and test environments.
200
222
 
@@ -766,7 +788,7 @@ try {
766
788
  console.log("Message id was: ", messageId)
767
789
  }).on("error", (err, messageId) => {
768
790
  console.error("Error was: ", err.message)
769
- }).on("return", (messageId) => {
791
+ }).on("return", (message) => {
770
792
  console.warn("Message was returned: ", message.properties.messageId)
771
793
  })
772
794
  } catch (err) {
@@ -817,6 +839,39 @@ When you publish a message using a confirm channel, amqplib will wait for an ack
817
839
  }
818
840
  ```
819
841
 
842
+ #### Aborting
843
+ Rascal uses a channel pool to publish messages. Access to the channel pool is synchronised via an in memory queue, which will be paused if the connection to the broker is temporarily lost. Consequently instead of erroring, publishes will be held until the connection is re-established. If you would rather abort under these circumstances, you can listen for the publication 'paused' event, and call `publication.abort()`. When the connection is re-established any aborted messages will be dropped instead of published.
844
+
845
+ ```js
846
+ broker.publish("p1", "some message", (err, publication) => {
847
+ if (err) throw err; // publication didn't exist
848
+ publication.on("success", (messageId) => {
849
+ console.log("Message id was: ", messageId)
850
+ }).on("error", (err, messageId) => {
851
+ console.error("Error was: ", err.message)
852
+ }).on("paused", (messageId) => {
853
+ console.warn("Publication was paused. Aborting message: ", messageId)
854
+ publication.abort();
855
+ })
856
+ })
857
+ ```
858
+
859
+ ```js
860
+ try {
861
+ const publication = await broker.publish("p1", "some message")
862
+ publication.on("success", (messageId) => {
863
+ console.log("Message id was: ", messageId)
864
+ }).on("error", (err, messageId) => {
865
+ console.error("Error was: ", err.message)
866
+ }).on("paused", (messageId) => {
867
+ console.warn("Publication was paused. Aborting message: ", messageId)
868
+ publication.abort();
869
+ })
870
+ } catch (err) {
871
+ // publication didn't exist
872
+ }
873
+ ```
874
+
820
875
  #### Encrypting messages
821
876
  Rascal can be configured to automatically encrypt outbound messages.
822
877
  ```json
@@ -10,8 +10,7 @@ module.exports = {
10
10
 
11
11
  // Define the vhost connection parameters. Specify multiple entries for cluster.
12
12
  // Rascal will randomise the list, and cycle through the entries until it finds one that works
13
- "connections": [
14
- {
13
+ "connections": [{
15
14
  "url": "amqp://does-not-exist-1b9935d9-5066-4b13-84dc-a8e2bb618154:5672/customer-vhost"
16
15
  },
17
16
  {
@@ -22,17 +21,17 @@ module.exports = {
22
21
  "heartbeat": 1
23
22
  },
24
23
  socketOptions: {
25
- timeout: 1000
24
+ timeout: 1000
26
25
  }
27
26
  }
28
27
  ],
29
28
 
30
29
  // Define exchanges within the registration vhost
31
30
  "exchanges": [
32
- "service", // Shared exchange for all services within this vhost
33
- "delay", // To delay failed messages before a retry
34
- "retry", // To retry failed messages a up to maximum number of times
35
- "dead_letters" // When retring fails messages end up here
31
+ "service", // Shared exchange for all services within this vhost
32
+ "delay", // To delay failed messages before a retry
33
+ "retry", // To retry failed messages a up to maximum number of times
34
+ "dead_letters" // When retring fails messages end up here
36
35
  ],
37
36
 
38
37
  // Define queues within the registration vhost
@@ -149,7 +148,7 @@ module.exports = {
149
148
  // providing the consumer configuration has a matching profile.
150
149
  "encryption": "well-known-v1"
151
150
  }
152
- }
151
+ },
153
152
 
154
153
  // Configure confirm channel pools. See https://www.npmjs.com/package/generic-pool
155
154
  // The demo application doesn't publish using regular channels. A regular pool will be created by default, but
@@ -167,26 +166,22 @@ module.exports = {
167
166
  "recovery": {
168
167
 
169
168
  // Deferred retry is a good strategy for temporary (connection timeout) or unknown errors
170
- "deferred_retry": [
171
- {
172
- "strategy": "forward",
173
- "attempts": 10,
174
- "publication": "retry_in_1m",
175
- "xDeathFix": true // See https://github.com/rabbitmq/rabbitmq-server/issues/161
176
- }, {
177
- "strategy": "nack"
178
- }
179
- ],
169
+ "deferred_retry": [{
170
+ "strategy": "forward",
171
+ "attempts": 10,
172
+ "publication": "retry_in_1m",
173
+ "xDeathFix": true // See https://github.com/rabbitmq/rabbitmq-server/issues/161
174
+ }, {
175
+ "strategy": "nack"
176
+ }],
180
177
 
181
178
  // Republishing with immediate nack returns the message to the original queue but decorates
182
179
  // it with error headers. The next time Rascal encounters the message it immedately nacks it
183
180
  // causing it to be routed to the services dead letter queue
184
- "dead_letter": [
185
- {
186
- "strategy": "republish",
187
- "immediateNack": true
188
- }
189
- ]
181
+ "dead_letter": [{
182
+ "strategy": "republish",
183
+ "immediateNack": true
184
+ }]
190
185
  },
191
186
  // Define counter(s) for counting redeliveries
192
187
  "redeliveries": {
@@ -1,8 +1,8 @@
1
1
  module.exports = {
2
2
  vhosts: {
3
3
  "/": {
4
- "publicationChannelPools": {
5
- "regularPool": {
4
+ publicationChannelPools: {
5
+ regularPool: {
6
6
  max: 10,
7
7
  min: 5,
8
8
  autostart: true
@@ -20,18 +20,18 @@ module.exports = {
20
20
  "demo_ex[a.b.c] -> demo_q"
21
21
  ],
22
22
  publications: {
23
- "demo_pub": {
24
- "exchange": "demo_ex",
25
- "routingKey": "a.b.c",
26
- "confirm": false,
27
- "options": {
28
- "persistent": false
23
+ demo_pub: {
24
+ exchange: "demo_ex",
25
+ routingKey: "a.b.c",
26
+ confirm: false,
27
+ options: {
28
+ persistent: false
29
29
  }
30
30
  }
31
31
  },
32
32
  subscriptions: {
33
- "demo_sub": {
34
- "queue": "demo_q"
33
+ demo_sub: {
34
+ queue: "demo_q"
35
35
  }
36
36
  }
37
37
  }
@@ -1,24 +1,24 @@
1
1
  module.exports = {
2
- vhosts: {
3
- "/": {
4
- connection: {
5
- heartbeat: 1,
6
- socketOptions: {
7
- timeout: 1000
8
- }
9
- },
10
- exchanges: [""],
11
- queues: ["demo_q"],
12
- publications: {
13
- "demo_pub": {
14
- "exchange": ""
15
- }
16
- },
17
- subscriptions: {
18
- "demo_sub": {
19
- "queue": "demo_q"
20
- }
21
- }
2
+ vhosts: {
3
+ "/": {
4
+ connection: {
5
+ heartbeat: 1,
6
+ socketOptions: {
7
+ timeout: 1000
22
8
  }
9
+ },
10
+ exchanges: [""],
11
+ queues: ["demo_q"],
12
+ publications: {
13
+ demo_pub: {
14
+ exchange: ""
15
+ }
16
+ },
17
+ subscriptions: {
18
+ demo_sub: {
19
+ queue: "demo_q"
20
+ }
21
+ }
23
22
  }
23
+ }
24
24
  }
@@ -1,22 +1,22 @@
1
1
  module.exports = {
2
- vhosts: {
3
- "/": {
4
- exchanges: ["demo_ex"],
5
- queues: ["demo_q"],
6
- bindings: [
7
- "demo_ex[a.b.c] -> demo_q"
8
- ],
9
- publications: {
10
- "demo_pub": {
11
- "exchange": "demo_ex",
12
- "routingKey": "a.b.c"
13
- }
14
- },
15
- subscriptions: {
16
- "demo_sub": {
17
- "queue": "demo_q"
18
- }
19
- }
2
+ vhosts: {
3
+ "/": {
4
+ exchanges: ["demo_ex"],
5
+ queues: ["demo_q"],
6
+ bindings: [
7
+ "demo_ex[a.b.c] -> demo_q"
8
+ ],
9
+ publications: {
10
+ demo_pub: {
11
+ exchange: "demo_ex",
12
+ routingKey: "a.b.c"
20
13
  }
14
+ },
15
+ subscriptions: {
16
+ demo_sub: {
17
+ queue: "demo_q"
18
+ }
19
+ }
21
20
  }
22
- }
21
+ }
22
+ }
@@ -1,28 +1,28 @@
1
1
  module.exports = {
2
- vhosts: {
3
- "/": {
4
- connection: {
5
- heartbeat: 1,
6
- socketOptions: {
7
- timeout: 1000
8
- }
9
- },
10
- exchanges: ["demo_ex"],
11
- queues: ["demo_q"],
12
- bindings: [
13
- "demo_ex[a.b.c] -> demo_q"
14
- ],
15
- publications: {
16
- "demo_pub": {
17
- "exchange": "demo_ex",
18
- "routingKey": "a.b.c"
19
- }
20
- },
21
- subscriptions: {
22
- "demo_sub": {
23
- "queue": "demo_q"
24
- }
25
- }
2
+ vhosts: {
3
+ "/": {
4
+ connection: {
5
+ heartbeat: 1,
6
+ socketOptions: {
7
+ timeout: 1000
26
8
  }
9
+ },
10
+ exchanges: ["demo_ex"],
11
+ queues: ["demo_q"],
12
+ bindings: [
13
+ "demo_ex[a.b.c] -> demo_q"
14
+ ],
15
+ publications: {
16
+ demo_pub: {
17
+ exchange: "demo_ex",
18
+ routingKey: "a.b.c"
19
+ }
20
+ },
21
+ subscriptions: {
22
+ demo_sub: {
23
+ queue: "demo_q"
24
+ }
25
+ }
27
26
  }
27
+ }
28
28
  }
@@ -18,17 +18,17 @@ module.exports = {
18
18
  "demo_ex[a.b.c] -> demo_q"
19
19
  ],
20
20
  publications: {
21
- "demo_pub": {
22
- "exchange": "demo_ex",
23
- "routingKey": "a.b.c",
24
- "options": {
25
- "persistent": false
21
+ demo_pub: {
22
+ exchange: "demo_ex",
23
+ routingKey: "a.b.c",
24
+ options: {
25
+ persistent: false
26
26
  }
27
27
  }
28
28
  },
29
29
  subscriptions: {
30
- "demo_sub": {
31
- "queue": "demo_q"
30
+ demo_sub: {
31
+ queue: "demo_q"
32
32
  }
33
33
  }
34
34
  }
@@ -13,6 +13,7 @@ var stub = require('../counters/stub');
13
13
  var inMemory = require('../counters/inMemory');
14
14
  var inMemoryCluster = require('../counters/inMemoryCluster').worker;
15
15
  var setTimeoutUnref = require('../utils/setTimeoutUnref');
16
+ var maxInterval = 2147483647;
16
17
 
17
18
  module.exports = {
18
19
  create: function create(config, components, next) {
@@ -50,6 +51,7 @@ function Broker(config, components) {
50
51
  subscriptions = {};
51
52
  sessions = [];
52
53
  init(config, { broker: self, components: { counters: counters } }, function(err, config, ctx) {
54
+ self.keepActive = setInterval(_.noop, maxInterval);
53
55
  setImmediate(function() {
54
56
  next(err, self);
55
57
  });
@@ -95,6 +97,7 @@ function Broker(config, components) {
95
97
  shutdownVhost(config, { vhost: vhost }, callback);
96
98
  }, function(err) {
97
99
  if (err) return next(err);
100
+ clearInterval(self.keepActive);
98
101
  debug('Finished shutting down broker');
99
102
  next();
100
103
  });
@@ -2,8 +2,8 @@ var debug = require('debug')('rascal:Publication');
2
2
  var format = require('util').format;
3
3
  var _ = require('lodash');
4
4
  var uuid = require('uuid').v4;
5
- var EventEmitter = require('events').EventEmitter;
6
5
  var crypto = require('crypto');
6
+ var PublicationSession = require('./PublicationSession');
7
7
  var setTimeoutUnref = require('../utils/setTimeoutUnref');
8
8
 
9
9
  module.exports = {
@@ -17,7 +17,7 @@ module.exports = {
17
17
 
18
18
  if (config.hasOwnProperty('exchange') && config.confirm) return new Publication(vhost, borrowConfirmChannel, returnConfirmChannel, destroyConfirmChannel, publishToConfirmExchange, config).init(next);
19
19
  if (config.hasOwnProperty('exchange')) return new Publication(vhost, borrowChannel, returnChannel, destroyChannel, publishToExchange, config).init(next);
20
- if (config.queue && config.confirm) return new Publication(vhost, borrowConfirmChannel, destroyConfirmChannel, returnConfirmChannel, sendToConfirmQueue, config).init(next);
20
+ if (config.queue && config.confirm) return new Publication(vhost, borrowConfirmChannel, returnConfirmChannel, destroyConfirmChannel, sendToConfirmQueue, config).init(next);
21
21
  if (config.queue) return new Publication(vhost, borrowChannel, returnChannel, destroyChannel, sendToQueue, config).init(next);
22
22
  },
23
23
  };
@@ -30,7 +30,7 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
30
30
 
31
31
  this.init = function(next) {
32
32
  debug('Initialising publication: %s', config.name);
33
- return next(null, self);
33
+ next(null, self);
34
34
  };
35
35
 
36
36
  this.publish = function(payload, overrides, next) {
@@ -39,7 +39,7 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
39
39
  publishConfig.options.contentType = publishConfig.options.contentType || content.type;
40
40
  publishConfig.options.messageId = publishConfig.options.messageId || uuid();
41
41
 
42
- return publishConfig.encryption
42
+ publishConfig.encryption
43
43
  ? _publishEncrypted(content.buffer, publishConfig, next)
44
44
  : _publish(content.buffer, publishConfig, next);
45
45
  };
@@ -87,32 +87,39 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
87
87
  }
88
88
 
89
89
  function _publish(buffer, publishConfig, next) {
90
- var emitter = new EventEmitter();
91
90
  var messageId = publishConfig.options.messageId;
91
+ var session = new PublicationSession(vhost, messageId);
92
92
  borrowChannelFn(function(err, channel) {
93
- if (err) return emitter.emit('error', err, messageId);
94
- var errorHandler = _.once(handleChannelError.bind(null, channel, messageId, emitter, config));
95
- var returnHandler = emitter.emit.bind(emitter, 'return');
93
+ session._removePausedListener();
94
+ if (err) return session.emit('error', err, messageId);
95
+ if (session.isAborted()) return abortPublish(channel, messageId);
96
+ var errorHandler = _.once(handleChannelError.bind(null, channel, messageId, session, config));
97
+ var returnHandler = session.emit.bind(session, 'return');
96
98
  addListeners(channel, errorHandler, returnHandler);
97
99
  try {
98
100
  publishFn(channel, buffer, publishConfig, function(err, ok) {
99
101
  if (err) {
100
102
  destroyChannel(channel, errorHandler, returnHandler);
101
- return emitter.emit('error', err, messageId);
103
+ return session.emit('error', err, messageId);
102
104
  }
103
105
 
104
106
  ok ? returnChannel(channel, errorHandler, returnHandler)
105
107
  : deferReturnChannel(channel, errorHandler, returnHandler);
106
108
 
107
- emitter.emit('success', messageId);
109
+ session.emit('success', messageId);
108
110
  });
109
111
  } catch(err) {
110
112
  returnChannel(channel, errorHandler, returnHandler);
111
- return emitter.emit('error', err, messageId);
113
+ return session.emit('error', err, messageId);
112
114
  };
113
115
  });
114
116
 
115
- next(null, emitter);
117
+ next(null, session);
118
+ }
119
+
120
+ function abortPublish(channel, messageId) {
121
+ debug('Publication of message: %s was aborted', messageId);
122
+ returnChannelFn(channel);
116
123
  }
117
124
 
118
125
  function returnChannel(channel, errorHandler, returnHandler) {
@@ -0,0 +1,36 @@
1
+ var debug = require('debug')('rascal:SubscriberSession');
2
+ var EventEmitter = require('events').EventEmitter;
3
+ var inherits = require('util').inherits;
4
+
5
+ module.exports = PublicationSession;
6
+
7
+ inherits(PublicationSession, EventEmitter);
8
+
9
+ function PublicationSession(vhost, messageId) {
10
+
11
+ var self = this;
12
+ var aborted = false;
13
+
14
+ this.abort = function() {
15
+ aborted = true;
16
+ };
17
+
18
+ this.isAborted = function() {
19
+ return aborted;
20
+ };
21
+
22
+ this._removePausedListener = function() {
23
+ vhost.removeListener('paused',emitPaused);
24
+ };
25
+
26
+ function emitPaused() {
27
+ self.emit('paused', messageId);
28
+ }
29
+
30
+ vhost.on('paused', emitPaused);
31
+
32
+ self.on('newListener', function(event) {
33
+ if (event !== 'paused') return;
34
+ if (vhost.isPaused()) emitPaused();
35
+ });
36
+ }
package/lib/amqp/Vhost.js CHANGED
@@ -3,7 +3,6 @@ var format = require('util').format;
3
3
  var inherits = require('util').inherits;
4
4
  var EventEmitter = require('events').EventEmitter;
5
5
  var async = require('async');
6
- var forwardEvents = require('forward-emitter');
7
6
  var genericPool = require('generic-pool');
8
7
  var tasks = require('./tasks');
9
8
  var uuid = require('uuid').v4;
@@ -33,6 +32,7 @@ function Vhost(config) {
33
32
  var purge = async.compose(tasks.closeConnection, tasks.closeChannel, tasks.purgeQueues, tasks.createChannel, tasks.createConnection);
34
33
  var nuke = async.compose(tasks.closeConnection, tasks.closeChannel, tasks.deleteQueues, tasks.deleteExchanges, tasks.createChannel, tasks.createConnection);
35
34
  var timer = backoff({});
35
+ var paused = true;
36
36
 
37
37
  this.name = config.name;
38
38
  this.connectionIndex = 0;
@@ -45,22 +45,22 @@ function Vhost(config) {
45
45
 
46
46
  init(config, { connectionIndex: self.connectionIndex }, function(err, config, ctx) {
47
47
  if (err) return next(err);
48
- self.emit('connect');
49
-
50
- attachErrorHandlers(ctx.connection, config);
51
48
 
52
- forwardEvents(ctx.connection, self, function(eventName) {
53
- return eventName === 'blocked' || eventName === 'unblocked';
54
- });
55
- debug('vhost: %s was initialised with connection: %s', self.name, ctx.connection._rascal_id);
56
49
  connection = ctx.connection;
57
50
  self.connectionIndex = ctx.connectionIndex;
58
51
  connectionConfig = ctx.connectionConfig;
59
52
  timer = backoff(ctx.connectionConfig.retry);
60
53
 
54
+ attachErrorHandlers(config);
55
+ forwardRabbitMQConnectionEvents();
61
56
  ensureChannelPools();
62
57
  resumeChannelAllocation();
63
58
 
59
+ debug('vhost: %s was initialised with connection: %s', self.name, connection._rascal_id);
60
+
61
+ self.emit('connect');
62
+ self.emit('vhost_initialised', getConnectionDetails());
63
+
64
64
  return next(null, self);
65
65
  });
66
66
  return self;
@@ -162,6 +162,10 @@ function Vhost(config) {
162
162
  confirmChannelPool.destroy(channel);
163
163
  };
164
164
 
165
+ this.isPaused = function() {
166
+ return paused;
167
+ };
168
+
165
169
  function createChannelPool(options) {
166
170
  var pool, poolQueue;
167
171
  var mode = getChannelMode(options.confirm);
@@ -326,12 +330,25 @@ function Vhost(config) {
326
330
  channelCreator.pause();
327
331
  regularChannelPool && regularChannelPool.pause();
328
332
  confirmChannelPool && confirmChannelPool.pause();
333
+ paused = true;
334
+ self.emit('paused', { vhost: self.name });
329
335
  }
330
336
 
331
337
  function resumeChannelAllocation() {
332
338
  channelCreator.resume();
333
339
  regularChannelPool && regularChannelPool.resume();
334
340
  confirmChannelPool && confirmChannelPool.resume();
341
+ paused = false;
342
+ self.emit('resumed', { vhost: self.name });
343
+ }
344
+
345
+ function forwardRabbitMQConnectionEvents() {
346
+ connection.on('blocked', function(reason) {
347
+ self.emit('blocked', reason, getConnectionDetails());
348
+ });
349
+ connection.on('unblocked', function() {
350
+ self.emit('unblocked', getConnectionDetails());
351
+ });
335
352
  }
336
353
 
337
354
  function ensureChannelPools() {
@@ -350,7 +367,7 @@ function Vhost(config) {
350
367
  ], next);
351
368
  }
352
369
 
353
- function attachErrorHandlers(connection, config) {
370
+ function attachErrorHandlers(config) {
354
371
  connection.removeAllListeners('error');
355
372
  var errorHandler = _.once(handleConnectionError.bind(null, connection, config));
356
373
  connection.once('error', errorHandler);
@@ -359,10 +376,10 @@ function Vhost(config) {
359
376
 
360
377
  function handleConnectionError(borked, config, err) {
361
378
  debug('Handling connection error: %s initially from connection: %s, %s', err.message, borked._rascal_id, connectionConfig.loggableUrl);
362
- self.emit('disconnect');
363
379
  pauseChannelAllocation();
364
380
  connection = undefined;
365
- self.emit('error', err);
381
+ self.emit('disconnect');
382
+ self.emit('error', err, getConnectionDetails());
366
383
  connectionConfig.retry && self.init(function(err) {
367
384
  if (!err) return;
368
385
  var delay = timer.next();
@@ -370,4 +387,8 @@ function Vhost(config) {
370
387
  setTimeoutUnref(handleConnectionError.bind(null, borked, config, err), delay);
371
388
  });
372
389
  }
390
+
391
+ function getConnectionDetails() {
392
+ return { vhost: self.name, connectionUrl: connectionConfig.loggableUrl };
393
+ }
373
394
  }
@@ -0,0 +1,114 @@
1
+ module.exports = {
2
+ defaults: {
3
+ vhosts: {
4
+ publicationChannelPools: {
5
+ regularPool: {
6
+ autostart: false,
7
+ max: 5,
8
+ min: 1,
9
+ evictionRunIntervalMillis: 10000,
10
+ idleTimeoutMillis: 60000,
11
+ testOnBorrow: true,
12
+ },
13
+ confirmPool: {
14
+ autostart: false,
15
+ max: 5,
16
+ min: 1,
17
+ evictionRunIntervalMillis: 10000,
18
+ idleTimeoutMillis: 60000,
19
+ testOnBorrow: true,
20
+ },
21
+ },
22
+ connectionStrategy: 'random',
23
+ connection: {
24
+ slashes: true,
25
+ protocol: 'amqp',
26
+ hostname: 'localhost',
27
+ user: 'guest',
28
+ password: 'guest',
29
+ port: '5672',
30
+ options: {
31
+ },
32
+ retry: {
33
+ min: 1000,
34
+ max: 60000,
35
+ factor: 2,
36
+ strategy: 'exponential',
37
+ },
38
+ management: {
39
+ slashes: true,
40
+ protocol: "http",
41
+ port: 15672,
42
+ options: {
43
+ },
44
+ },
45
+ },
46
+ exchanges: {
47
+ assert: true,
48
+ type: 'topic',
49
+ options: {
50
+ },
51
+ },
52
+ queues: {
53
+ assert: true,
54
+ options: {
55
+ arguments: {
56
+ },
57
+ },
58
+ },
59
+ bindings: {
60
+ destinationType: 'queue',
61
+ bindingKey: '#',
62
+ options: {
63
+ },
64
+ },
65
+ },
66
+ publications: {
67
+ vhost: '/',
68
+ confirm: true,
69
+ timeout: 10000,
70
+ options: {
71
+ persistent: true,
72
+ mandatory: true,
73
+ },
74
+ },
75
+ subscriptions: {
76
+ vhost: '/',
77
+ prefetch: 10,
78
+ retry: {
79
+ min: 1000,
80
+ max: 60000,
81
+ factor: 2,
82
+ strategy: 'exponential',
83
+ },
84
+ redeliveries: {
85
+ limit: 100,
86
+ timeout: 1000,
87
+ counter: 'stub',
88
+ },
89
+ deferCloseChannel: 10000,
90
+ options: {
91
+ },
92
+ },
93
+ redeliveries: {
94
+ counters: {
95
+ stub: {},
96
+ inMemory: {
97
+ size: 1000,
98
+ },
99
+ },
100
+ },
101
+ shovels: {
102
+ },
103
+ },
104
+ publications: {
105
+ },
106
+ subscriptions: {
107
+ },
108
+ redeliveries: {
109
+ counters: {
110
+ stub: {
111
+ },
112
+ },
113
+ },
114
+ };
@@ -3,14 +3,14 @@ var format = require('util').format;
3
3
  var url = require('url');
4
4
  var _ = require('lodash');
5
5
  var uuid = require('uuid').v4;
6
- var emptyConfig = require('./empty');
6
+ var baseline = require('./baseline');
7
7
  var fqn = require('./fqn');
8
8
  var XRegExp = require('xregexp');
9
9
  var freeze = require('deep-freeze');
10
10
 
11
11
  module.exports = _.curry(function(rascalConfig, next) {
12
12
 
13
- rascalConfig = _.defaultsDeep(rascalConfig, emptyConfig, { publications: {}, subscriptions: {}, redeliveries: { counters: { stub: {} }}});
13
+ rascalConfig = _.defaultsDeep(rascalConfig, baseline);
14
14
 
15
15
  var err;
16
16
  var connectionIndexes = {};
@@ -1,99 +1,21 @@
1
1
  module.exports = {
2
2
  defaults: {
3
3
  vhosts: {
4
- publicationChannelPools: {
5
- regularPool: {
6
- autostart: false,
7
- max: 5,
8
- min: 1,
9
- evictionRunIntervalMillis: 10000,
10
- idleTimeoutMillis: 60000,
11
- testOnBorrow: true,
12
- },
13
- confirmPool: {
14
- autostart: false,
15
- max: 5,
16
- min: 1,
17
- evictionRunIntervalMillis: 10000,
18
- idleTimeoutMillis: 60000,
19
- testOnBorrow: true,
20
- },
21
- },
22
- connectionStrategy: 'random',
23
4
  connection: {
24
- slashes: true,
25
- protocol: 'amqp',
26
- hostname: 'localhost',
27
- user: 'guest',
28
- password: 'guest',
29
- port: '5672',
30
5
  options: {
31
6
  heartbeat: 10,
32
7
  connection_timeout: 10000,
33
8
  channelMax: 100,
34
9
  },
35
- retry: {
36
- min: 1000,
37
- max: 60000,
38
- factor: 2,
39
- strategy: 'exponential',
40
- },
41
10
  socketOptions: {
42
11
  timeout: 10000,
43
12
  },
44
13
  management: {
45
- slashes: true,
46
- protocol: "http",
47
- port: 15672,
48
14
  options: {
49
15
  timeout: 1000,
50
16
  },
51
17
  },
52
18
  },
53
- exchanges: {
54
- assert: true,
55
- type: 'topic',
56
- },
57
- queues: {
58
- assert: true,
59
- },
60
- bindings: {
61
- destinationType: 'queue',
62
- bindingKey: '#',
63
- },
64
- },
65
- publications: {
66
- vhost: '/',
67
- confirm: true,
68
- timeout: 10000,
69
- options: {
70
- persistent: true,
71
- mandatory: true,
72
- },
73
- },
74
- subscriptions: {
75
- vhost: '/',
76
- prefetch: 10,
77
- retry: {
78
- min: 1000,
79
- max: 60000,
80
- factor: 2,
81
- strategy: 'exponential',
82
- },
83
- redeliveries: {
84
- limit: 100,
85
- timeout: 1000,
86
- counter: 'stub',
87
- },
88
- deferCloseChannel: 10000,
89
- },
90
- redeliveries: {
91
- counters: {
92
- stub: {},
93
- inMemory: {
94
- size: 1000,
95
- },
96
- },
97
19
  },
98
20
  },
99
21
  };
@@ -33,7 +33,6 @@ module.exports = _.defaultsDeep({
33
33
  },
34
34
  redeliveries: {
35
35
  "counters": {
36
- "stub": {},
37
36
  "inMemory": {
38
37
  "size": 1000,
39
38
  },
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "rascal",
3
- "version": "9.1.2",
3
+ "version": "9.4.0",
4
4
  "description": "A config driven wrapper for amqplib supporting multi-host connections, automatic error recovery, redelivery flood protection, transparent encryption / decryption, channel pooling and publication timeouts",
5
5
  "main": "index.js",
6
6
  "dependencies": {
7
- "async": "^3.1.0",
7
+ "async": "^3.2.0",
8
8
  "debug": "^4.1.1",
9
9
  "deep-freeze": "0.0.1",
10
10
  "forward-emitter": "^0.1.1",
@@ -12,21 +12,22 @@
12
12
  "lodash": "^4.17.15",
13
13
  "lru-cache": "^5.1.1",
14
14
  "safe-json-parse": "^4.0.0",
15
- "stashback": "^1.1.0",
16
- "superagent": "^5.2.1",
17
- "uuid": "^3.3.3",
18
- "xregexp": "^4.2.4"
15
+ "snyk": "^1.316.2",
16
+ "stashback": "^1.1.2",
17
+ "superagent": "^5.2.2",
18
+ "uuid": "^8.0.0",
19
+ "xregexp": "^4.3.0"
19
20
  },
20
21
  "devDependencies": {
21
22
  "amqplib": "^0.5.5",
22
- "chalk": "^3.0.0",
23
+ "chalk": "^4.0.0",
23
24
  "chance": "^1.1.4",
24
25
  "eslint": "^6.8.0",
25
26
  "eslint-config-imperative": "^3.0.0",
26
27
  "eslint-plugin-imperative": "^3.0.0",
27
- "husky": "^4.0.9",
28
+ "husky": "^4.2.5",
28
29
  "mocha": "^7.1.1",
29
- "nyc": "^15.0.0",
30
+ "nyc": "^15.0.1",
30
31
  "random-readable": "^1.0.1"
31
32
  },
32
33
  "peerDependencies": {
@@ -45,7 +46,9 @@
45
46
  "lint": "eslint .",
46
47
  "docker": "docker run -d --name rascal-rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management",
47
48
  "coverage": "nyc report --reporter lcov --reporter html",
48
- "codeclimate": "(test -e .codeclimate && npm run coverage && source .codeclimate && codeclimate-test-reporter < coverage/lcov.info) || echo skipping codeclimate"
49
+ "codeclimate": "(test -e .codeclimate && npm run coverage && source .codeclimate && codeclimate-test-reporter < coverage/lcov.info) || echo skipping codeclimate",
50
+ "snyk-protect": "snyk protect",
51
+ "prepare": "npm run snyk-protect"
49
52
  },
50
53
  "keywords": [
51
54
  "amqplib",
@@ -78,5 +81,6 @@
78
81
  "recursive": true,
79
82
  "slow": 2000,
80
83
  "timeout": 5000
81
- }
84
+ },
85
+ "snyk": true
82
86
  }
@@ -1,38 +0,0 @@
1
- module.exports = {
2
- defaults: {
3
- vhosts: {
4
- connection: {
5
- management: {
6
- },
7
- },
8
- exchanges: {
9
- options: {
10
- },
11
- },
12
- queues: {
13
- options: {
14
- arguments: {
15
- },
16
- },
17
- },
18
- bindings: {
19
- options: {
20
- },
21
- },
22
- },
23
- publications: {
24
- options: {
25
- },
26
- },
27
- subscriptions: {
28
- options: {
29
- },
30
- },
31
- shovels: {
32
- },
33
- },
34
- redeliveries: {
35
- counters: {
36
- },
37
- },
38
- };