rascal 16.0.0 → 16.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Change Log
2
2
 
3
+ ## 16.1.0
4
+
5
+ - Added concurrency option for managing RabbitMQ topology. Rascal will create and use upto this number of channels when asserting/checking/deleting/purging queues, exchanges and bindings.
6
+
3
7
  ## 16.0.0
4
8
 
5
9
  - Automatically set replyTo message property when a publication references a replyTo queue
package/README.md CHANGED
@@ -692,6 +692,7 @@ Sometimes you want to publish a message, and have the consumer of the message se
692
692
  }
693
693
  },
694
694
  "publications": {
695
+ "exchange": "e1",
695
696
  "replyTo": "q1"
696
697
  }
697
698
  }
@@ -1711,6 +1712,10 @@ is equivalent to...
1711
1712
  }
1712
1713
  ```
1713
1714
 
1715
+ ### Concurrency
1716
+
1717
+ If you have a high number of exchanges, queues and bindings you may wish to initialise Rascal using multiple channels to improve startup time. Do this per vhost by setting the `concurrency` option to the number of channels you want to create and use.
1718
+
1714
1719
  ### Connect
1715
1720
 
1716
1721
  Rascal is a rich pub/sub wrapper and as such hides much of the amqplib [channel api](https://www.squaremobius.net/amqp.node/channel_api.html#channel). If you need to access this you can programmatically establish a connection to a vhost as follows.
package/lib/amqp/Vhost.js CHANGED
@@ -26,10 +26,10 @@ function Vhost(vhostConfig, components) {
26
26
  let confirmChannelPool;
27
27
  const channelCreator = async.queue(createChannel, 1);
28
28
 
29
- const init = async.compose(tasks.closeChannel, tasks.applyBindings, tasks.purgeQueues, tasks.checkQueues, tasks.assertQueues, tasks.checkExchanges, tasks.assertExchanges, tasks.createChannel, tasks.createConnection, tasks.checkVhost, tasks.assertVhost);
29
+ const init = async.compose(tasks.closeChannels, tasks.applyBindings, tasks.purgeQueues, tasks.checkQueues, tasks.assertQueues, tasks.checkExchanges, tasks.assertExchanges, tasks.createChannels, tasks.createConnection, tasks.checkVhost, tasks.assertVhost);
30
30
  const connect = async.compose(tasks.createConnection);
31
- const purge = async.compose(tasks.closeConnection, tasks.closeChannel, tasks.purgeQueues, tasks.createChannel, tasks.createConnection);
32
- const nuke = async.compose(tasks.closeConnection, tasks.closeChannel, tasks.deleteQueues, tasks.deleteExchanges, tasks.createChannel, tasks.createConnection);
31
+ const purge = async.compose(tasks.closeConnection, tasks.closeChannels, tasks.purgeQueues, tasks.createChannels, tasks.createConnection);
32
+ const nuke = async.compose(tasks.closeConnection, tasks.closeChannels, tasks.deleteQueues, tasks.deleteExchanges, tasks.createChannels, tasks.createConnection);
33
33
  let timer = backoff({});
34
34
  let paused = true;
35
35
  let shuttingDown = false;
@@ -9,10 +9,12 @@ module.exports = _.curry((config, ctx, next) => {
9
9
  exchange: bindExchange,
10
10
  };
11
11
 
12
- async.eachSeries(
12
+ async.eachOfLimit(
13
13
  _.values(config.bindings),
14
- (binding, callback) => {
15
- bind[binding.destinationType](config, ctx.channel, binding, callback);
14
+ config.concurrency,
15
+ (binding, index, cb) => {
16
+ const channel = ctx.channels[index % config.concurrency];
17
+ bind[binding.destinationType](config, channel, binding, cb);
16
18
  },
17
19
  (err) => {
18
20
  next(err, config, ctx);
@@ -3,10 +3,12 @@ const _ = require('lodash');
3
3
  const async = require('async');
4
4
 
5
5
  module.exports = _.curry((config, ctx, next) => {
6
- async.eachSeries(
6
+ async.eachOfLimit(
7
7
  _.keys(config.exchanges),
8
- (name, callback) => {
9
- assertExchange(ctx.channel, config.exchanges[name], callback);
8
+ config.concurrency,
9
+ (name, index, cb) => {
10
+ const channel = ctx.channels[index % config.concurrency];
11
+ assertExchange(channel, config.exchanges[name], cb);
10
12
  },
11
13
  (err) => {
12
14
  next(err, config, ctx);
@@ -18,5 +20,9 @@ function assertExchange(channel, config, next) {
18
20
  if (!config.assert) return next();
19
21
  if (config.fullyQualifiedName === '') return next();
20
22
  debug('Asserting exchange: %s', config.fullyQualifiedName);
21
- channel.assertExchange(config.fullyQualifiedName, config.type, config.options, next);
23
+ channel.assertExchange(config.fullyQualifiedName, config.type, config.options, (err) => {
24
+ if (err) return next(err);
25
+ debug('Asserted exchange: %s', config.fullyQualifiedName);
26
+ next();
27
+ });
22
28
  }
@@ -3,10 +3,12 @@ const _ = require('lodash');
3
3
  const async = require('async');
4
4
 
5
5
  module.exports = _.curry((config, ctx, next) => {
6
- async.eachSeries(
6
+ async.eachOfLimit(
7
7
  _.keys(config.queues),
8
- (name, callback) => {
9
- assertQueue(ctx.channel, config.queues[name], callback);
8
+ config.concurrency,
9
+ (name, index, cb) => {
10
+ const channel = ctx.channels[index % config.concurrency];
11
+ assertQueue(channel, config.queues[name], cb);
10
12
  },
11
13
  (err) => {
12
14
  next(err, config, ctx);
@@ -3,10 +3,12 @@ const _ = require('lodash');
3
3
  const async = require('async');
4
4
 
5
5
  module.exports = _.curry((config, ctx, next) => {
6
- async.eachSeries(
6
+ async.eachOfLimit(
7
7
  _.keys(config.exchanges),
8
- (name, callback) => {
9
- checkExchange(ctx.channel, config.exchanges[name], callback);
8
+ config.concurrency,
9
+ (name, index, cb) => {
10
+ const channel = ctx.channels[index % config.concurrency];
11
+ checkExchange(channel, config.exchanges[name], cb);
10
12
  },
11
13
  (err) => {
12
14
  next(err, config, ctx);
@@ -3,10 +3,12 @@ const _ = require('lodash');
3
3
  const async = require('async');
4
4
 
5
5
  module.exports = _.curry((config, ctx, next) => {
6
- async.eachSeries(
6
+ async.eachOfLimit(
7
7
  _.keys(config.queues),
8
- (name, callback) => {
9
- checkQueue(ctx.channel, config.queues[name], callback);
8
+ config.concurrency,
9
+ (name, index, cb) => {
10
+ const channel = ctx.channels[index % config.concurrency];
11
+ checkQueue(channel, config.queues[name], cb);
10
12
  },
11
13
  (err) => {
12
14
  next(err, config, ctx);
@@ -0,0 +1,18 @@
1
+ const debug = require('debug')('rascal:tasks:closeChannels');
2
+ const async = require('async');
3
+ const _ = require('lodash');
4
+
5
+ module.exports = _.curry((config, ctx, next) => {
6
+ debug('Closing %d channels', ctx.channels.length);
7
+
8
+ async.each(
9
+ ctx.channels,
10
+ (channel, cb) => {
11
+ channel.close(cb);
12
+ },
13
+ (err) => {
14
+ delete ctx.channels;
15
+ return next(err, config, ctx);
16
+ }
17
+ );
18
+ });
@@ -0,0 +1,19 @@
1
+ const debug = require('debug')('rascal:tasks:createChannel');
2
+ const async = require('async');
3
+ const _ = require('lodash');
4
+
5
+ module.exports = _.curry((config, ctx, next) => {
6
+ debug('Creating %d channels', config.concurrency);
7
+
8
+ async.times(
9
+ config.concurrency,
10
+ (index, cb) => {
11
+ ctx.connection.createChannel(cb);
12
+ },
13
+ (err, channels) => {
14
+ if (err) return next(err, config, ctx);
15
+ ctx.channels = channels;
16
+ next(null, config, ctx);
17
+ }
18
+ );
19
+ });
@@ -3,10 +3,12 @@ const _ = require('lodash');
3
3
  const async = require('async');
4
4
 
5
5
  module.exports = _.curry((config, ctx, next) => {
6
- async.eachSeries(
6
+ async.eachOfLimit(
7
7
  _.keys(config.exchanges),
8
- (name, callback) => {
9
- deleteExchange(ctx.channel, config.exchanges[name], callback);
8
+ config.concurrency,
9
+ (name, index, cb) => {
10
+ const channel = ctx.channels[index % config.concurrency];
11
+ deleteExchange(channel, config.exchanges[name], cb);
10
12
  },
11
13
  (err) => {
12
14
  next(err, config, ctx);
@@ -3,10 +3,12 @@ const _ = require('lodash');
3
3
  const async = require('async');
4
4
 
5
5
  module.exports = _.curry((config, ctx, next) => {
6
- async.eachSeries(
6
+ async.eachOfLimit(
7
7
  _.keys(config.queues),
8
- (name, callback) => {
9
- deleteQueue(ctx.channel, config.queues[name], callback);
8
+ config.concurrency,
9
+ (name, index, cb) => {
10
+ const channel = ctx.channels[index % config.concurrency];
11
+ deleteQueue(channel, config.queues[name], cb);
10
12
  },
11
13
  (err) => {
12
14
  next(err, config, ctx);
@@ -6,9 +6,9 @@ exports.bounceVhost = require('./bounceVhost');
6
6
  exports.checkExchanges = require('./checkExchanges');
7
7
  exports.checkQueues = require('./checkQueues');
8
8
  exports.checkVhost = require('./checkVhost');
9
- exports.closeChannel = require('./closeChannel');
9
+ exports.closeChannels = require('./closeChannels');
10
10
  exports.closeConnection = require('./closeConnection');
11
- exports.createChannel = require('./createChannel');
11
+ exports.createChannels = require('./createChannels');
12
12
  exports.createConnection = require('./createConnection');
13
13
  exports.deleteExchanges = require('./deleteExchanges');
14
14
  exports.deleteQueues = require('./deleteQueues');
@@ -3,10 +3,12 @@ const _ = require('lodash');
3
3
  const async = require('async');
4
4
 
5
5
  module.exports = _.curry((config, ctx, next) => {
6
- async.eachSeries(
6
+ async.eachOfLimit(
7
7
  _.keys(config.queues),
8
- (name, callback) => {
9
- purgeQueue(ctx.channel, config.queues[name], ctx, callback);
8
+ config.concurrency,
9
+ (name, index, cb) => {
10
+ const channel = ctx.channels[index % config.concurrency];
11
+ purgeQueue(channel, config.queues[name], ctx, cb);
10
12
  },
11
13
  (err) => {
12
14
  next(err, config, ctx);
@@ -1,6 +1,7 @@
1
1
  module.exports = {
2
2
  defaults: {
3
3
  vhosts: {
4
+ concurrency: 1,
4
5
  publicationChannelPools: {
5
6
  regularPool: {
6
7
  autostart: false,
@@ -43,6 +43,7 @@ module.exports = _.curry((rascalConfig, next) => {
43
43
  {
44
44
  name,
45
45
  namespace: rascalConfig.defaults.vhosts.namespace,
46
+ concurrency: rascalConfig.defaults.vhosts.concurrency,
46
47
  connectionStrategy: rascalConfig.defaults.vhosts.connectionStrategy,
47
48
  publicationChannelPools: rascalConfig.defaults.vhosts.publicationChannelPools,
48
49
  },
@@ -57,6 +57,10 @@
57
57
  "$ref": "#/definitions/connection"
58
58
  }
59
59
  },
60
+ "concurrency": {
61
+ "type": "integer",
62
+ "minimum": 1
63
+ },
60
64
  "exchanges": {
61
65
  "oneOf": [
62
66
  {
@@ -20,7 +20,7 @@ module.exports = _.curry((config, next) => {
20
20
  }
21
21
 
22
22
  function validateVhost(vhost, vhostName) {
23
- validateAttributes('Vhost', vhost, vhostName, ['defaults', 'namespace', 'name', 'publicationChannelPools', 'connection', 'connections', 'connectionStrategy', 'exchanges', 'queues', 'bindings', 'check', 'assert']);
23
+ validateAttributes('Vhost', vhost, vhostName, ['defaults', 'namespace', 'name', 'concurrency', 'publicationChannelPools', 'connection', 'connections', 'connectionStrategy', 'exchanges', 'queues', 'bindings', 'check', 'assert']);
24
24
  validateConnectionStrategy(vhost.connectionStrategy, vhostName);
25
25
  validateConnectionAttributes(vhost.connection, vhostName, ['slashes', 'protocol', 'hostname', 'user', 'password', 'port', 'vhost', 'options', 'retry', 'auth', 'pathname', 'query', 'url', 'loggableUrl', 'management']);
26
26
  validateManagementConnectionAttributes(_.get(vhost), 'connection.management', vhostName, ['slashes', 'protocol', 'hostname', 'user', 'password', 'port', 'vhost', 'options', 'auth', 'pathname', 'query', 'url', 'loggableUrl']);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rascal",
3
- "version": "16.0.0",
3
+ "version": "16.1.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": {
@@ -1,12 +0,0 @@
1
- const debug = require('debug')('rascal:tasks:closeChannel');
2
- const _ = require('lodash');
3
-
4
- module.exports = _.curry((config, ctx, next) => {
5
- debug('Closing channel');
6
-
7
- ctx.channel.close((err) => {
8
- if (err) return next(err, config, ctx);
9
- delete ctx.channel;
10
- next(null, config, ctx);
11
- });
12
- });
@@ -1,12 +0,0 @@
1
- const debug = require('debug')('rascal:tasks:createChannel');
2
- const _ = require('lodash');
3
-
4
- module.exports = _.curry((config, ctx, next) => {
5
- debug('Creating channel');
6
-
7
- ctx.connection.createChannel((err, channel) => {
8
- if (err) return next(err, config, ctx);
9
- ctx.channel = channel;
10
- next(null, config, ctx);
11
- });
12
- });