rascal 16.1.1 → 16.2.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,14 @@
1
1
  # Change Log
2
2
 
3
+ ## 16.2.0
4
+
5
+ - Disable indirect dependabot updates (they're almost pointless for modules since package-lock.json isn't published)
6
+ - Support acknowledging / rejecting all outstanding messages
7
+
8
+ ## 16.1.2
9
+
10
+ - Add consumer tag subscription option to JSON schema
11
+
3
12
  ## 16.1.1
4
13
 
5
14
  - Updated README
package/README.md CHANGED
@@ -1181,7 +1181,7 @@ await subscription = broker.subscribe("s1", { prefetch: 10, retry: false })
1181
1181
 
1182
1182
  The arguments passed to the message event handler are `function(message, content, ackOrNack)`, where message is the raw message, the content (a buffer, text, or object) and an ackOrNack callback. This ackOrNack callback should only be used for messages which were not `{ "options": { "noAck": true } }` by the subscription configuration or the options passed to `broker.subscribe`. For more details on acking or nacking messages see [Message Acknowledgement and Recovery Strategies](#message-acknowledgement-and-recovery-strategies).
1183
1183
 
1184
- > As with publications, you can nest subscriptions inside the vhost block. Rascal creates default subscriptions for every queue so providing you don't need to specify any additional options you don't need to include a subscriptions block at all.
1184
+ As with publications, you can nest subscriptions inside the vhost block. Rascal creates default subscriptions for every queue so providing you don't need to specify any additional options you don't need to include a subscriptions block at all.
1185
1185
 
1186
1186
  #### Subscribe All
1187
1187
 
@@ -1412,7 +1412,7 @@ See [here](https://www.npmjs.com/package/rascal-redis-counter) for a redis backe
1412
1412
 
1413
1413
  #### Message Acknowledgement and Recovery Strategies
1414
1414
 
1415
- For messages which are not auto-acknowledged (the default) calling `ackOrNack()` with no arguments will acknowledge it. Calling `ackOrNack(err)` will nack the message using Rascal's default recovery strategy (nack with requeue). Calling `ackOrNack(err, recoveryOptions)` will trigger the specified recovery strategy or strategies.
1415
+ For messages which are not auto-acknowledged (the default) calling `ackOrNack()` with no arguments will acknowledge it. Calling `ackOrNack(err)` will nack the message using Rascal's default recovery strategy (nack with requeue). Calling `ackOrNack(err, recoveryOptions)` will trigger the specified recovery strategy or strategies. You can also acknowledge all outstanding messages on the channel by calling `ackOrNack(null, { all: true })`.
1416
1416
 
1417
1417
  When using the callback API, you can call ackOrNack without a callback and errors will be emitted by the subscription. Alternatively you can specify a callback as the final argument irrespective of what other arguments you provide.
1418
1418
 
@@ -1424,7 +1424,11 @@ When using the promises API, ackOrNack will work as for the callback API unless
1424
1424
  ackOrNack(err, { strategy: 'nack' });
1425
1425
  ```
1426
1426
 
1427
- Nack causes the message to be discarded or routed to a dead letter exchange if configured.
1427
+ Nack causes the message to be discarded or routed to a dead letter exchange if configured. You can also negatively acknowledge all outstanding messages on a channel as follows
1428
+
1429
+ ```js
1430
+ ackOrNac(err, { strategy: 'nack', all: true });
1431
+ ```
1428
1432
 
1429
1433
  ##### Nack with Requeue
1430
1434
 
package/dependabot.yml ADDED
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'npm'
4
+ directory: '/'
5
+ allow:
6
+ - dependency-type: 'direct'
@@ -5,11 +5,11 @@ const async = require('async');
5
5
  const setTimeoutUnref = require('../utils/setTimeoutUnref');
6
6
 
7
7
  module.exports = function SubscriptionRecovery(broker, vhost) {
8
- this.handle = function (session, message, err, recoveryProcess, next) {
8
+ this.handle = function (session, message, err, recoveryOptions, next) {
9
9
  debug('Handling subscriber error for message: %s', message.properties.messageId);
10
10
 
11
11
  async.eachSeries(
12
- [].concat(recoveryProcess || []).concat({ strategy: 'fallback-nack' }),
12
+ [].concat(recoveryOptions || []).concat({ strategy: 'fallback-nack' }),
13
13
  (recoveryConfig, cb) => {
14
14
  debug('Attempting to recover message: %s using strategy: %s', message.properties.messageId, recoveryConfig.strategy);
15
15
 
@@ -40,7 +40,8 @@ module.exports = function SubscriptionRecovery(broker, vhost) {
40
40
  {
41
41
  name: 'ack',
42
42
  execute(session, message, err, strategyConfig, next) {
43
- session._ack(message, (err) => {
43
+ const ackFn = strategyConfig.all ? session._nackAll.bind(session) : session._nack.bind(session);
44
+ ackFn(message, (err) => {
44
45
  next(err, true);
45
46
  });
46
47
  },
@@ -48,7 +49,8 @@ module.exports = function SubscriptionRecovery(broker, vhost) {
48
49
  {
49
50
  name: 'nack',
50
51
  execute(session, message, err, strategyConfig, next) {
51
- session._nack(message, { requeue: strategyConfig.requeue }, (err) => {
52
+ const nackFn = strategyConfig.all ? session._nackAll.bind(session) : session._nack.bind(session);
53
+ nackFn(message, { requeue: strategyConfig.requeue }, (err) => {
52
54
  next(err, true);
53
55
  });
54
56
  },
@@ -95,6 +95,14 @@ function SubscriberSession(sequentialChannelOperations, config) {
95
95
  });
96
96
  };
97
97
 
98
+ this._resetUnacknowledgedMessageCount = function (consumerTag) {
99
+ if (config.options.noAck) return;
100
+ withConsumerChannel(consumerTag, (channel, __, entry) => {
101
+ entry.unacknowledgedMessages = 0;
102
+ debug('Channel: %s has %s unacknowledged messages', channel._rascal_id, entry.unacknowledgedMessages);
103
+ });
104
+ };
105
+
98
106
  this._ack = function (message, next) {
99
107
  withConsumerChannel(
100
108
  message.fields.consumerTag,
@@ -112,6 +120,23 @@ function SubscriberSession(sequentialChannelOperations, config) {
112
120
  );
113
121
  };
114
122
 
123
+ this._ackAll = function (message, next) {
124
+ withConsumerChannel(
125
+ message.fields.consumerTag,
126
+ (channel) => {
127
+ debug('Acknowledging all messages on channel: %s', message.properties.messageId, channel._rascal_id);
128
+ channel.ackAll();
129
+ self._resetUnacknowledgedMessageCount(message.fields.consumerTag);
130
+ setImmediate(next);
131
+ },
132
+ () => {
133
+ setImmediate(() => {
134
+ next(new Error('The channel has been closed. Unable to ack messages'));
135
+ });
136
+ }
137
+ );
138
+ };
139
+
115
140
  this._nack = function (message, options, next) {
116
141
  if (arguments.length === 2) return self._nack(arguments[0], {}, arguments[1]);
117
142
  withConsumerChannel(
@@ -130,6 +155,24 @@ function SubscriberSession(sequentialChannelOperations, config) {
130
155
  );
131
156
  };
132
157
 
158
+ this._nackAll = function (message, options, next) {
159
+ if (arguments.length === 2) return self._nackAll(arguments[0], {}, arguments[1]);
160
+ withConsumerChannel(
161
+ message.fields.consumerTag,
162
+ (channel) => {
163
+ debug('Not acknowledging all messages with requeue: %s on channel: %s', message.properties.messageId, !!options.requeue, channel._rascal_id);
164
+ channel.nack(message, true, !!options.requeue);
165
+ self._resetUnacknowledgedMessageCount(message.fields.consumerTag);
166
+ setImmediate(next);
167
+ },
168
+ () => {
169
+ setImmediate(() => {
170
+ next(new Error('The channel has been closed. Unable to nack messages'));
171
+ });
172
+ }
173
+ );
174
+ };
175
+
133
176
  function withCurrentChannel(fn, altFn) {
134
177
  const entry = _.chain(channels)
135
178
  .values()
@@ -208,24 +208,28 @@ function Subscription(broker, vhost, subscriptionConfig, counter) {
208
208
  return ackOrNack.bind(null, session, message);
209
209
  }
210
210
 
211
- function ackOrNack(session, message, err, recovery, next) {
211
+ function ackOrNack(session, message, err, options, next) {
212
212
  if (arguments.length === 2) return ackOrNack(session, message, undefined, undefined, emitOnError.bind(null, session));
213
213
  if (arguments.length === 3 && _.isFunction(arguments[2])) return ackOrNack(session, message, undefined, undefined, arguments[2]);
214
214
  if (arguments.length === 3) return ackOrNack(session, message, err, undefined, emitOnError.bind(null, session));
215
215
  if (arguments.length === 4 && _.isFunction(arguments[3])) return ackOrNack(session, message, err, undefined, arguments[3]);
216
- if (arguments.length === 4) return ackOrNack(session, message, err, recovery, emitOnError.bind(null, session));
217
- err ? subscriberError.handle(session, message, err, recovery, next) : session._ack(message, next);
216
+ if (arguments.length === 4) return ackOrNack(session, message, err, options, emitOnError.bind(null, session));
217
+ if (err) return subscriberError.handle(session, message, err, options, next);
218
+ if (options && options.all) return session._ackAll(message, next);
219
+ session._ack(message, next);
218
220
  }
219
221
 
220
- function ackOrNackP(session, message, err, recovery) {
222
+ function ackOrNackP(session, message, err, options) {
221
223
  if (arguments.length === 2) return ackOrNackP(session, message, undefined, undefined);
222
224
  if (arguments.length === 3) return ackOrNackP(session, message, err, undefined);
223
225
 
224
226
  return new Promise((resolve, reject) => {
225
- const cb = function (err) {
227
+ const next = function (err) {
226
228
  err ? reject(err) : resolve();
227
229
  };
228
- err ? subscriberError.handle(session, message, err, recovery, cb) : session._ack(message, cb);
230
+ if (err) subscriberError.handle(session, message, err, options, next);
231
+ else if (options && options.all) session._ackAll(message, next);
232
+ else session._ack(message, next);
229
233
  });
230
234
  }
231
235
 
@@ -619,6 +619,9 @@
619
619
  },
620
620
  "arguments": {
621
621
  "type": "object"
622
+ },
623
+ "consumerTag": {
624
+ "type": "string"
622
625
  }
623
626
  }
624
627
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rascal",
3
- "version": "16.1.1",
3
+ "version": "16.2.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": {