rascal 13.1.2 → 13.1.3
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/.husky/pre-commit +1 -1
- package/.prettierrc.json +1 -0
- package/CHANGELOG.md +195 -1
- package/README.md +630 -395
- package/examples/advanced/cluster.js +8 -8
- package/examples/advanced/config.js +117 -114
- package/examples/advanced/handlers/deleteUser.js +23 -17
- package/examples/advanced/handlers/saveUser.js +38 -32
- package/examples/advanced/index.js +105 -78
- package/examples/busy-publisher/config.js +14 -17
- package/examples/busy-publisher/index.js +27 -22
- package/examples/default-exchange/config.js +10 -10
- package/examples/default-exchange/index.js +27 -18
- package/examples/mocha/config.js +9 -11
- package/examples/mocha/test.js +42 -35
- package/examples/promises/config.js +11 -13
- package/examples/promises/index.js +24 -17
- package/examples/simple/config.js +16 -18
- package/examples/simple/index.js +25 -23
- package/index.js +7 -7
- package/lib/amqp/Broker.js +154 -99
- package/lib/amqp/BrokerAsPromised.js +56 -35
- package/lib/amqp/Publication.js +219 -78
- package/lib/amqp/PublicationSession.js +13 -14
- package/lib/amqp/SubscriberError.js +293 -132
- package/lib/amqp/SubscriberSession.js +95 -56
- package/lib/amqp/SubscriberSessionAsPromised.js +4 -6
- package/lib/amqp/Subscription.js +328 -109
- package/lib/amqp/Vhost.js +341 -170
- package/lib/amqp/tasks/applyBindings.js +51 -18
- package/lib/amqp/tasks/assertExchanges.js +20 -11
- package/lib/amqp/tasks/assertQueues.js +13 -9
- package/lib/amqp/tasks/assertVhost.js +21 -17
- package/lib/amqp/tasks/bounceVhost.js +1 -1
- package/lib/amqp/tasks/checkExchanges.js +13 -9
- package/lib/amqp/tasks/checkQueues.js +13 -9
- package/lib/amqp/tasks/checkVhost.js +21 -17
- package/lib/amqp/tasks/closeChannel.js +3 -4
- package/lib/amqp/tasks/closeConnection.js +3 -3
- package/lib/amqp/tasks/createChannel.js +3 -4
- package/lib/amqp/tasks/createConnection.js +71 -53
- package/lib/amqp/tasks/deleteExchanges.js +14 -10
- package/lib/amqp/tasks/deleteQueues.js +13 -9
- package/lib/amqp/tasks/deleteVhost.js +26 -17
- package/lib/amqp/tasks/forewarnVhost.js +1 -1
- package/lib/amqp/tasks/index.js +25 -25
- package/lib/amqp/tasks/initCounters.js +18 -13
- package/lib/amqp/tasks/initPublications.js +17 -13
- package/lib/amqp/tasks/initShovels.js +29 -20
- package/lib/amqp/tasks/initSubscriptions.js +23 -13
- package/lib/amqp/tasks/initVhosts.js +21 -17
- package/lib/amqp/tasks/nukeVhost.js +1 -1
- package/lib/amqp/tasks/purgeQueues.js +13 -9
- package/lib/amqp/tasks/purgeVhost.js +1 -1
- package/lib/amqp/tasks/shutdownVhost.js +1 -1
- package/lib/backoff/exponential.js +9 -8
- package/lib/backoff/index.js +3 -3
- package/lib/backoff/linear.js +5 -7
- package/lib/config/baseline.js +25 -35
- package/lib/config/configure.js +274 -101
- package/lib/config/fqn.js +3 -3
- package/lib/config/tests.js +32 -29
- package/lib/config/validate.js +460 -70
- package/lib/counters/inMemory.js +3 -3
- package/lib/counters/inMemoryCluster.js +48 -30
- package/lib/counters/index.js +4 -4
- package/lib/counters/stub.js +2 -3
- package/lib/management/client.js +47 -17
- package/lib/utils/setTimeoutUnref.js +1 -1
- package/package.json +12 -4
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
const EventEmitter = require(
|
|
2
|
-
const inherits = require(
|
|
3
|
-
const forwardEvents = require(
|
|
1
|
+
const EventEmitter = require("events").EventEmitter;
|
|
2
|
+
const inherits = require("util").inherits;
|
|
3
|
+
const forwardEvents = require("forward-emitter");
|
|
4
4
|
|
|
5
5
|
module.exports = SubscriberSessionAsPromised;
|
|
6
6
|
|
|
7
7
|
inherits(SubscriberSessionAsPromised, EventEmitter);
|
|
8
8
|
|
|
9
9
|
function SubscriberSessionAsPromised(session) {
|
|
10
|
-
|
|
11
10
|
forwardEvents(session, this);
|
|
12
11
|
|
|
13
12
|
this.name = session.name;
|
|
14
13
|
this.config = session.config;
|
|
15
14
|
|
|
16
|
-
this.cancel = function() {
|
|
15
|
+
this.cancel = function () {
|
|
17
16
|
return new Promise((resolve, reject) => {
|
|
18
17
|
session.cancel((err) => {
|
|
19
18
|
if (err) return reject(err);
|
|
@@ -21,5 +20,4 @@ function SubscriberSessionAsPromised(session) {
|
|
|
21
20
|
});
|
|
22
21
|
});
|
|
23
22
|
};
|
|
24
|
-
|
|
25
23
|
}
|
package/lib/amqp/Subscription.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const debug = require(
|
|
2
|
-
const _ = require(
|
|
3
|
-
const safeParse = require(
|
|
4
|
-
const SubscriberSession = require(
|
|
5
|
-
const SubscriberError = require(
|
|
6
|
-
const format = require(
|
|
7
|
-
const backoff = require(
|
|
8
|
-
const crypto = require(
|
|
9
|
-
const async = require(
|
|
10
|
-
const setTimeoutUnref = require(
|
|
1
|
+
const debug = require("debug")("rascal:Subscription");
|
|
2
|
+
const _ = require("lodash");
|
|
3
|
+
const safeParse = require("safe-json-parse/callback");
|
|
4
|
+
const SubscriberSession = require("./SubscriberSession");
|
|
5
|
+
const SubscriberError = require("./SubscriberError");
|
|
6
|
+
const format = require("util").format;
|
|
7
|
+
const backoff = require("../backoff");
|
|
8
|
+
const crypto = require("crypto");
|
|
9
|
+
const async = require("async");
|
|
10
|
+
const setTimeoutUnref = require("../utils/setTimeoutUnref");
|
|
11
11
|
|
|
12
12
|
module.exports = {
|
|
13
13
|
create(broker, vhost, counter, config, next) {
|
|
@@ -25,23 +25,23 @@ function Subscription(broker, vhost, config, counter) {
|
|
|
25
25
|
|
|
26
26
|
this.name = config.name;
|
|
27
27
|
|
|
28
|
-
this.init = function(next) {
|
|
29
|
-
debug(
|
|
28
|
+
this.init = function (next) {
|
|
29
|
+
debug("Initialising subscription: %s", config.name);
|
|
30
30
|
return next(null, self);
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
this.subscribe = function(overrides, next) {
|
|
33
|
+
this.subscribe = function (overrides, next) {
|
|
34
34
|
const session = new SubscriberSession(sequentialChannelOperations, config);
|
|
35
35
|
subscribeLater(session, _.defaultsDeep(overrides, config));
|
|
36
36
|
return next(null, session);
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
function subscribeLater(session, config) {
|
|
40
|
-
session.on(
|
|
41
|
-
if (event !==
|
|
40
|
+
session.on("newListener", (event) => {
|
|
41
|
+
if (event !== "message") return;
|
|
42
42
|
subscribeNow(session, config, (err) => {
|
|
43
|
-
if (err) return session.emit(
|
|
44
|
-
session.emit(
|
|
43
|
+
if (err) return session.emit("error", err);
|
|
44
|
+
session.emit("subscribed");
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
}
|
|
@@ -49,64 +49,115 @@ function Subscription(broker, vhost, config, counter) {
|
|
|
49
49
|
function subscribeNow(session, config, next) {
|
|
50
50
|
sequentialChannelOperations.push((done) => {
|
|
51
51
|
if (session.isCancelled()) {
|
|
52
|
-
debug(
|
|
52
|
+
debug("Subscription to queue: %s has been cancelled", config.queue);
|
|
53
53
|
return done();
|
|
54
54
|
}
|
|
55
|
-
debug(
|
|
55
|
+
debug("Subscribing to queue: %s", config.queue);
|
|
56
56
|
vhost.getChannel((err, channel) => {
|
|
57
57
|
if (err) return done(err);
|
|
58
58
|
if (!channel) return done();
|
|
59
59
|
|
|
60
60
|
if (config.prefetch) channel.prefetch(config.prefetch);
|
|
61
61
|
|
|
62
|
-
const removeErrorHandlers = attachErrorHandlers(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
const removeErrorHandlers = attachErrorHandlers(
|
|
63
|
+
channel,
|
|
64
|
+
session,
|
|
65
|
+
config
|
|
66
|
+
);
|
|
67
|
+
const onMessage = _onMessage.bind(
|
|
68
|
+
null,
|
|
69
|
+
session,
|
|
70
|
+
config,
|
|
71
|
+
removeErrorHandlers
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
channel.consume(
|
|
75
|
+
config.source,
|
|
76
|
+
onMessage,
|
|
77
|
+
config.options,
|
|
78
|
+
(err, response) => {
|
|
79
|
+
if (err) {
|
|
80
|
+
debug(
|
|
81
|
+
"Error subscribing to %s using channel: %s. %s",
|
|
82
|
+
config.source,
|
|
83
|
+
channel._rascal_id,
|
|
84
|
+
err.message
|
|
85
|
+
);
|
|
86
|
+
removeErrorHandlers();
|
|
87
|
+
return done(err);
|
|
88
|
+
}
|
|
89
|
+
session._open(channel, response.consumerTag, (err) => {
|
|
90
|
+
if (err) return done(err);
|
|
91
|
+
timer.reset();
|
|
92
|
+
done();
|
|
93
|
+
});
|
|
70
94
|
}
|
|
71
|
-
|
|
72
|
-
if (err) return done(err);
|
|
73
|
-
timer.reset();
|
|
74
|
-
done();
|
|
75
|
-
});
|
|
76
|
-
});
|
|
95
|
+
);
|
|
77
96
|
});
|
|
78
97
|
}, next);
|
|
79
98
|
}
|
|
80
99
|
|
|
81
100
|
function _onMessage(session, config, removeErrorHandlers, message) {
|
|
82
|
-
if (!message)
|
|
101
|
+
if (!message)
|
|
102
|
+
return handleConsumerCancel(session, config, removeErrorHandlers);
|
|
83
103
|
|
|
84
|
-
debug(
|
|
104
|
+
debug(
|
|
105
|
+
"Received message: %s from queue: %s",
|
|
106
|
+
message.properties.messageId,
|
|
107
|
+
config.queue
|
|
108
|
+
);
|
|
85
109
|
|
|
86
110
|
decorateWithRoutingHeaders(message);
|
|
87
111
|
if (immediateNack(message)) return ackOrNack(session, message, true);
|
|
88
112
|
|
|
89
113
|
decorateWithRedeliveries(message, (err) => {
|
|
90
114
|
if (err) return handleRedeliveriesError(err, session, message);
|
|
91
|
-
if (redeliveriesExceeded(message))
|
|
115
|
+
if (redeliveriesExceeded(message))
|
|
116
|
+
return handleRedeliveriesExceeded(session, message);
|
|
92
117
|
|
|
93
118
|
getContent(message, config, (err, content) => {
|
|
94
|
-
err
|
|
95
|
-
|
|
119
|
+
err
|
|
120
|
+
? handleContentError(session, message, err)
|
|
121
|
+
: session.emit(
|
|
122
|
+
"message",
|
|
123
|
+
message,
|
|
124
|
+
content,
|
|
125
|
+
getAckOrNack(session, message)
|
|
126
|
+
);
|
|
96
127
|
});
|
|
97
128
|
});
|
|
98
129
|
}
|
|
99
130
|
|
|
100
131
|
function getContent(message, config, next) {
|
|
101
132
|
if (message.properties.headers.rascal.encryption) {
|
|
102
|
-
const encryptionConfig =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
133
|
+
const encryptionConfig =
|
|
134
|
+
config.encryption[message.properties.headers.rascal.encryption.name];
|
|
135
|
+
if (!encryptionConfig)
|
|
136
|
+
return next(
|
|
137
|
+
new Error(
|
|
138
|
+
format(
|
|
139
|
+
"Unknown encryption profile: %s",
|
|
140
|
+
message.properties.headers.rascal.encryption.name
|
|
141
|
+
)
|
|
142
|
+
)
|
|
143
|
+
);
|
|
144
|
+
decrypt(
|
|
145
|
+
encryptionConfig.algorithm,
|
|
146
|
+
encryptionConfig.key,
|
|
147
|
+
message.properties.headers.rascal.encryption.iv,
|
|
148
|
+
message.content,
|
|
149
|
+
(err, unencrypted) => {
|
|
150
|
+
if (err) return next(err);
|
|
151
|
+
debug(
|
|
152
|
+
"Message was decrypted using encryption profile: %s",
|
|
153
|
+
message.properties.headers.rascal.encryption.name
|
|
154
|
+
);
|
|
155
|
+
const contentType =
|
|
156
|
+
config.contentType ||
|
|
157
|
+
message.properties.headers.rascal.encryption.originalContentType;
|
|
158
|
+
negotiateContent(contentType, unencrypted, next);
|
|
159
|
+
}
|
|
160
|
+
);
|
|
110
161
|
} else {
|
|
111
162
|
const contentType = config.contentType || message.properties.contentType;
|
|
112
163
|
negotiateContent(contentType, message.content, next);
|
|
@@ -114,16 +165,17 @@ function Subscription(broker, vhost, config, counter) {
|
|
|
114
165
|
}
|
|
115
166
|
|
|
116
167
|
function negotiateContent(contentType, content, next) {
|
|
117
|
-
if (contentType ===
|
|
118
|
-
if (contentType ===
|
|
168
|
+
if (contentType === "text/plain") return next(null, content.toString());
|
|
169
|
+
if (contentType === "application/json")
|
|
170
|
+
return safeParse(content.toString(), next);
|
|
119
171
|
return next(null, content);
|
|
120
172
|
}
|
|
121
173
|
|
|
122
174
|
function decrypt(algorithm, keyHex, ivHex, encrypted, next) {
|
|
123
175
|
let unencrypted;
|
|
124
176
|
try {
|
|
125
|
-
const key = Buffer.from(keyHex,
|
|
126
|
-
const iv = Buffer.from(ivHex,
|
|
177
|
+
const key = Buffer.from(keyHex, "hex");
|
|
178
|
+
const iv = Buffer.from(ivHex, "hex");
|
|
127
179
|
const cipher = crypto.createDecipheriv(algorithm, key, iv);
|
|
128
180
|
unencrypted = Buffer.concat([cipher.update(encrypted), cipher.final()]);
|
|
129
181
|
} catch (err) {
|
|
@@ -133,29 +185,93 @@ function Subscription(broker, vhost, config, counter) {
|
|
|
133
185
|
}
|
|
134
186
|
|
|
135
187
|
function handleContentError(session, message, err) {
|
|
136
|
-
debug(
|
|
188
|
+
debug(
|
|
189
|
+
"Error getting content for message %s: %s",
|
|
190
|
+
message.properties.messageId,
|
|
191
|
+
err.message
|
|
192
|
+
);
|
|
137
193
|
// Documentation wrongly specified 'invalid_content' instead of 'invalid_message' emitting both
|
|
138
|
-
if (
|
|
139
|
-
|
|
194
|
+
if (
|
|
195
|
+
session.emit(
|
|
196
|
+
"invalid_content",
|
|
197
|
+
err,
|
|
198
|
+
message,
|
|
199
|
+
getAckOrNack(session, message)
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
return;
|
|
203
|
+
if (
|
|
204
|
+
session.emit(
|
|
205
|
+
"invalid_message",
|
|
206
|
+
err,
|
|
207
|
+
message,
|
|
208
|
+
getAckOrNack(session, message)
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
return;
|
|
140
212
|
nackAndError(session, message, err);
|
|
141
213
|
}
|
|
142
214
|
|
|
143
215
|
function redeliveriesExceeded(message) {
|
|
144
|
-
return
|
|
216
|
+
return (
|
|
217
|
+
message.properties.headers.rascal.redeliveries > config.redeliveries.limit
|
|
218
|
+
);
|
|
145
219
|
}
|
|
146
220
|
|
|
147
221
|
function handleRedeliveriesError(err, session, message) {
|
|
148
|
-
debug(
|
|
149
|
-
|
|
150
|
-
|
|
222
|
+
debug(
|
|
223
|
+
"Error handling redeliveries of message %s: %s",
|
|
224
|
+
message.properties.messageId,
|
|
225
|
+
err.message
|
|
226
|
+
);
|
|
227
|
+
if (
|
|
228
|
+
session.emit(
|
|
229
|
+
"redeliveries_error",
|
|
230
|
+
err,
|
|
231
|
+
message,
|
|
232
|
+
getAckOrNack(session, message)
|
|
233
|
+
)
|
|
234
|
+
)
|
|
235
|
+
return;
|
|
236
|
+
if (
|
|
237
|
+
session.emit(
|
|
238
|
+
"redeliveries_exceeded",
|
|
239
|
+
err,
|
|
240
|
+
message,
|
|
241
|
+
getAckOrNack(session, message)
|
|
242
|
+
)
|
|
243
|
+
)
|
|
244
|
+
return;
|
|
151
245
|
nackAndError(session, message, err);
|
|
152
246
|
}
|
|
153
247
|
|
|
154
248
|
function handleRedeliveriesExceeded(session, message) {
|
|
155
|
-
const err = new Error(
|
|
249
|
+
const err = new Error(
|
|
250
|
+
format(
|
|
251
|
+
"Message %s has exceeded %d redeliveries",
|
|
252
|
+
message.properties.messageId,
|
|
253
|
+
config.redeliveries.limit
|
|
254
|
+
)
|
|
255
|
+
);
|
|
156
256
|
debug(err.message);
|
|
157
|
-
if (
|
|
158
|
-
|
|
257
|
+
if (
|
|
258
|
+
session.emit(
|
|
259
|
+
"redeliveries_exceeded",
|
|
260
|
+
err,
|
|
261
|
+
message,
|
|
262
|
+
getAckOrNack(session, message)
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
return;
|
|
266
|
+
if (
|
|
267
|
+
session.emit(
|
|
268
|
+
"redeliveries_error",
|
|
269
|
+
err,
|
|
270
|
+
message,
|
|
271
|
+
getAckOrNack(session, message)
|
|
272
|
+
)
|
|
273
|
+
)
|
|
274
|
+
return;
|
|
159
275
|
nackAndError(session, message, err);
|
|
160
276
|
}
|
|
161
277
|
|
|
@@ -163,7 +279,7 @@ function Subscription(broker, vhost, config, counter) {
|
|
|
163
279
|
ackOrNack(session, message, err, () => {
|
|
164
280
|
// Using setTimeout rather than process.nextTick as the latter fires before any IO.
|
|
165
281
|
// If the app shuts down before the IO has completed, the message will be rolled back
|
|
166
|
-
setTimeoutUnref(session.emit.bind(session,
|
|
282
|
+
setTimeoutUnref(session.emit.bind(session, "error", err));
|
|
167
283
|
});
|
|
168
284
|
}
|
|
169
285
|
|
|
@@ -174,14 +290,25 @@ function Subscription(broker, vhost, config, counter) {
|
|
|
174
290
|
message.properties.headers.rascal.originalVhost = vhost.name;
|
|
175
291
|
|
|
176
292
|
if (!message.properties.headers.rascal.restoreRoutingHeaders) return;
|
|
177
|
-
if (message.properties.headers.rascal.originalRoutingKey)
|
|
178
|
-
|
|
293
|
+
if (message.properties.headers.rascal.originalRoutingKey)
|
|
294
|
+
message.fields.routingKey =
|
|
295
|
+
message.properties.headers.rascal.originalRoutingKey;
|
|
296
|
+
if (message.properties.headers.rascal.originalExchange)
|
|
297
|
+
message.fields.exchange =
|
|
298
|
+
message.properties.headers.rascal.originalExchange;
|
|
179
299
|
}
|
|
180
300
|
|
|
181
301
|
function decorateWithRedeliveries(message, next) {
|
|
182
302
|
const once = _.once(next);
|
|
183
303
|
const timeout = setTimeoutUnref(() => {
|
|
184
|
-
once(
|
|
304
|
+
once(
|
|
305
|
+
new Error(
|
|
306
|
+
format(
|
|
307
|
+
"Redeliveries timed out after %dms",
|
|
308
|
+
config.redeliveries.timeout
|
|
309
|
+
)
|
|
310
|
+
)
|
|
311
|
+
);
|
|
185
312
|
}, config.redeliveries.timeout);
|
|
186
313
|
countRedeliveries(message, (err, redeliveries) => {
|
|
187
314
|
clearTimeout(timeout);
|
|
@@ -194,88 +321,180 @@ function Subscription(broker, vhost, config, counter) {
|
|
|
194
321
|
function countRedeliveries(message, next) {
|
|
195
322
|
if (!message.fields.redelivered) return next(null, 0);
|
|
196
323
|
if (!message.properties.messageId) return next(null, 0);
|
|
197
|
-
counter.incrementAndGet(
|
|
324
|
+
counter.incrementAndGet(
|
|
325
|
+
config.name + "/" + message.properties.messageId,
|
|
326
|
+
next
|
|
327
|
+
);
|
|
198
328
|
}
|
|
199
329
|
|
|
200
330
|
function immediateNack(message) {
|
|
201
|
-
if (
|
|
331
|
+
if (
|
|
332
|
+
_.get(message, [
|
|
333
|
+
"properties",
|
|
334
|
+
"headers",
|
|
335
|
+
"rascal",
|
|
336
|
+
"recovery",
|
|
337
|
+
message.properties.headers.rascal.originalQueue,
|
|
338
|
+
"immediateNack",
|
|
339
|
+
])
|
|
340
|
+
)
|
|
341
|
+
return true;
|
|
202
342
|
return false;
|
|
203
343
|
}
|
|
204
344
|
|
|
205
345
|
function getAckOrNack(session, message) {
|
|
206
|
-
if (!broker.promises || config.promisifyAckOrNack === false)
|
|
207
|
-
|
|
346
|
+
if (!broker.promises || config.promisifyAckOrNack === false)
|
|
347
|
+
return ackOrNack.bind(null, session, message);
|
|
348
|
+
if (config.promisifyAckOrNack)
|
|
349
|
+
return ackOrNackP.bind(null, session, message);
|
|
208
350
|
return ackOrNack.bind(null, session, message);
|
|
209
351
|
}
|
|
210
352
|
|
|
211
353
|
function ackOrNack(session, message, err, recovery, next) {
|
|
212
|
-
if (arguments.length === 2)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
354
|
+
if (arguments.length === 2)
|
|
355
|
+
return ackOrNack(
|
|
356
|
+
session,
|
|
357
|
+
message,
|
|
358
|
+
undefined,
|
|
359
|
+
undefined,
|
|
360
|
+
emitOnError.bind(null, session)
|
|
361
|
+
);
|
|
362
|
+
if (arguments.length === 3 && _.isFunction(arguments[2]))
|
|
363
|
+
return ackOrNack(session, message, undefined, undefined, arguments[2]);
|
|
364
|
+
if (arguments.length === 3)
|
|
365
|
+
return ackOrNack(
|
|
366
|
+
session,
|
|
367
|
+
message,
|
|
368
|
+
err,
|
|
369
|
+
undefined,
|
|
370
|
+
emitOnError.bind(null, session)
|
|
371
|
+
);
|
|
372
|
+
if (arguments.length === 4 && _.isFunction(arguments[3]))
|
|
373
|
+
return ackOrNack(session, message, err, undefined, arguments[3]);
|
|
374
|
+
if (arguments.length === 4)
|
|
375
|
+
return ackOrNack(
|
|
376
|
+
session,
|
|
377
|
+
message,
|
|
378
|
+
err,
|
|
379
|
+
recovery,
|
|
380
|
+
emitOnError.bind(null, session)
|
|
381
|
+
);
|
|
382
|
+
err
|
|
383
|
+
? subscriberError.handle(session, message, err, recovery, next)
|
|
384
|
+
: session._ack(message, next);
|
|
219
385
|
}
|
|
220
386
|
|
|
221
387
|
function ackOrNackP(session, message, err, recovery) {
|
|
222
|
-
if (arguments.length === 2)
|
|
223
|
-
|
|
388
|
+
if (arguments.length === 2)
|
|
389
|
+
return ackOrNackP(session, message, undefined, undefined);
|
|
390
|
+
if (arguments.length === 3)
|
|
391
|
+
return ackOrNackP(session, message, err, undefined);
|
|
224
392
|
|
|
225
393
|
return new Promise((resolve, reject) => {
|
|
226
|
-
const cb = function(err) {
|
|
227
|
-
|
|
228
|
-
|
|
394
|
+
const cb = function (err) {
|
|
395
|
+
err ? reject(err) : resolve();
|
|
396
|
+
};
|
|
397
|
+
err
|
|
398
|
+
? subscriberError.handle(session, message, err, recovery, cb)
|
|
399
|
+
: session._ack(message, cb);
|
|
229
400
|
});
|
|
230
401
|
}
|
|
231
402
|
|
|
232
403
|
function emitOnError(session, err) {
|
|
233
|
-
if (err) session.emit(
|
|
404
|
+
if (err) session.emit("error", err);
|
|
234
405
|
}
|
|
235
406
|
|
|
236
407
|
function attachErrorHandlers(channel, session, config) {
|
|
237
408
|
/* eslint-disable no-use-before-define */
|
|
238
409
|
const connection = channel.connection;
|
|
239
410
|
const removeErrorHandlers = _.once(() => {
|
|
240
|
-
channel.removeListener(
|
|
241
|
-
channel.on(
|
|
242
|
-
debug(
|
|
411
|
+
channel.removeListener("error", errorHandler);
|
|
412
|
+
channel.on("error", (err) => {
|
|
413
|
+
debug(
|
|
414
|
+
"Suppressing error on cancelled session: %s to prevent connection errors. %s",
|
|
415
|
+
channel._rascal_id,
|
|
416
|
+
err.message
|
|
417
|
+
);
|
|
243
418
|
});
|
|
244
|
-
connection.removeListener(
|
|
245
|
-
connection.removeListener(
|
|
419
|
+
connection.removeListener("error", errorHandler);
|
|
420
|
+
connection.removeListener("close", errorHandler);
|
|
246
421
|
});
|
|
247
|
-
const errorHandler = _.once(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
422
|
+
const errorHandler = _.once(
|
|
423
|
+
handleChannelError.bind(null, session, config, removeErrorHandlers, 0)
|
|
424
|
+
);
|
|
425
|
+
channel.on("error", errorHandler);
|
|
426
|
+
connection.once("error", errorHandler);
|
|
427
|
+
connection.once("close", errorHandler);
|
|
251
428
|
return removeErrorHandlers;
|
|
252
429
|
}
|
|
253
430
|
|
|
254
|
-
function handleChannelError(
|
|
255
|
-
|
|
431
|
+
function handleChannelError(
|
|
432
|
+
session,
|
|
433
|
+
config,
|
|
434
|
+
removeErrorHandlers,
|
|
435
|
+
attempts,
|
|
436
|
+
err
|
|
437
|
+
) {
|
|
438
|
+
debug(
|
|
439
|
+
"Handling channel error: %s from %s using channel: %s",
|
|
440
|
+
err.message,
|
|
441
|
+
config.name,
|
|
442
|
+
session._getRascalChannelId()
|
|
443
|
+
);
|
|
256
444
|
if (removeErrorHandlers) removeErrorHandlers();
|
|
257
|
-
session.emit(
|
|
258
|
-
config.retry &&
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
445
|
+
session.emit("error", err);
|
|
446
|
+
config.retry &&
|
|
447
|
+
subscribeNow(session, config, (err) => {
|
|
448
|
+
if (!err) return;
|
|
449
|
+
const delay = timer.next();
|
|
450
|
+
debug(
|
|
451
|
+
"Will attempt resubscription(%d) to %s in %dms",
|
|
452
|
+
attempts + 1,
|
|
453
|
+
config.name,
|
|
454
|
+
delay
|
|
455
|
+
);
|
|
456
|
+
session._schedule(
|
|
457
|
+
handleChannelError.bind(
|
|
458
|
+
null,
|
|
459
|
+
session,
|
|
460
|
+
config,
|
|
461
|
+
null,
|
|
462
|
+
attempts + 1,
|
|
463
|
+
err
|
|
464
|
+
),
|
|
465
|
+
delay
|
|
466
|
+
);
|
|
467
|
+
});
|
|
264
468
|
}
|
|
265
469
|
|
|
266
470
|
function handleConsumerCancel(session, config, removeErrorHandlers) {
|
|
267
|
-
debug(
|
|
471
|
+
debug(
|
|
472
|
+
"Received consumer cancel from %s using channel: %s",
|
|
473
|
+
config.name,
|
|
474
|
+
session._getRascalChannelId()
|
|
475
|
+
);
|
|
268
476
|
removeErrorHandlers();
|
|
269
477
|
session._close((err) => {
|
|
270
|
-
if (err) debug(
|
|
271
|
-
const cancelErr = new Error(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
478
|
+
if (err) debug("Error cancelling subscription: %s", err.message);
|
|
479
|
+
const cancelErr = new Error(
|
|
480
|
+
format("Subscription: %s was cancelled by the broker", config.name)
|
|
481
|
+
);
|
|
482
|
+
session.emit("cancelled", cancelErr) || session.emit("error", cancelErr);
|
|
483
|
+
config.retry &&
|
|
484
|
+
subscribeNow(session, config, (err) => {
|
|
485
|
+
if (!err) return;
|
|
486
|
+
const delay = timer.next();
|
|
487
|
+
debug(
|
|
488
|
+
"Will attempt resubscription(%d) to %s in %dms",
|
|
489
|
+
1,
|
|
490
|
+
config.name,
|
|
491
|
+
delay
|
|
492
|
+
);
|
|
493
|
+
session._schedule(
|
|
494
|
+
handleChannelError.bind(null, session, config, null, 1, err),
|
|
495
|
+
delay
|
|
496
|
+
);
|
|
497
|
+
});
|
|
279
498
|
});
|
|
280
499
|
}
|
|
281
500
|
}
|