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 +9 -0
- package/README.md +7 -3
- package/dependabot.yml +6 -0
- package/lib/amqp/SubscriberError.js +6 -4
- package/lib/amqp/SubscriberSession.js +43 -0
- package/lib/amqp/Subscription.js +10 -6
- package/lib/config/schema.json +3 -0
- package/package.json +1 -1
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
|
-
|
|
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
|
@@ -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,
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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()
|
package/lib/amqp/Subscription.js
CHANGED
|
@@ -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,
|
|
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,
|
|
217
|
-
err
|
|
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,
|
|
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
|
|
227
|
+
const next = function (err) {
|
|
226
228
|
err ? reject(err) : resolve();
|
|
227
229
|
};
|
|
228
|
-
err
|
|
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
|
|
package/lib/config/schema.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rascal",
|
|
3
|
-
"version": "16.
|
|
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": {
|