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
package/lib/amqp/Vhost.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const debug = require(
|
|
2
|
-
const format = require(
|
|
3
|
-
const inherits = require(
|
|
4
|
-
const EventEmitter = require(
|
|
5
|
-
const async = require(
|
|
6
|
-
const genericPool = require(
|
|
7
|
-
const tasks = require(
|
|
8
|
-
const uuid = require(
|
|
9
|
-
const _ = require(
|
|
10
|
-
const backoff = require(
|
|
11
|
-
const setTimeoutUnref = require(
|
|
1
|
+
const debug = require("debug")("rascal:Vhost");
|
|
2
|
+
const format = require("util").format;
|
|
3
|
+
const inherits = require("util").inherits;
|
|
4
|
+
const EventEmitter = require("events").EventEmitter;
|
|
5
|
+
const async = require("async");
|
|
6
|
+
const genericPool = require("generic-pool");
|
|
7
|
+
const tasks = require("./tasks");
|
|
8
|
+
const uuid = require("uuid").v4;
|
|
9
|
+
const _ = require("lodash");
|
|
10
|
+
const backoff = require("../backoff");
|
|
11
|
+
const setTimeoutUnref = require("../utils/setTimeoutUnref");
|
|
12
12
|
|
|
13
13
|
module.exports = {
|
|
14
14
|
create(config, next) {
|
|
@@ -19,7 +19,6 @@ module.exports = {
|
|
|
19
19
|
inherits(Vhost, EventEmitter);
|
|
20
20
|
|
|
21
21
|
function Vhost(config) {
|
|
22
|
-
|
|
23
22
|
const self = this;
|
|
24
23
|
let connection;
|
|
25
24
|
let connectionConfig;
|
|
@@ -27,10 +26,35 @@ function Vhost(config) {
|
|
|
27
26
|
let confirmChannelPool;
|
|
28
27
|
const channelCreator = async.queue(createChannel, 1);
|
|
29
28
|
|
|
30
|
-
const init = async.compose(
|
|
29
|
+
const init = async.compose(
|
|
30
|
+
tasks.closeChannel,
|
|
31
|
+
tasks.applyBindings,
|
|
32
|
+
tasks.purgeQueues,
|
|
33
|
+
tasks.checkQueues,
|
|
34
|
+
tasks.assertQueues,
|
|
35
|
+
tasks.checkExchanges,
|
|
36
|
+
tasks.assertExchanges,
|
|
37
|
+
tasks.createChannel,
|
|
38
|
+
tasks.createConnection,
|
|
39
|
+
tasks.checkVhost,
|
|
40
|
+
tasks.assertVhost
|
|
41
|
+
);
|
|
31
42
|
const connect = async.compose(tasks.createConnection);
|
|
32
|
-
const purge = async.compose(
|
|
33
|
-
|
|
43
|
+
const purge = async.compose(
|
|
44
|
+
tasks.closeConnection,
|
|
45
|
+
tasks.closeChannel,
|
|
46
|
+
tasks.purgeQueues,
|
|
47
|
+
tasks.createChannel,
|
|
48
|
+
tasks.createConnection
|
|
49
|
+
);
|
|
50
|
+
const nuke = async.compose(
|
|
51
|
+
tasks.closeConnection,
|
|
52
|
+
tasks.closeChannel,
|
|
53
|
+
tasks.deleteQueues,
|
|
54
|
+
tasks.deleteExchanges,
|
|
55
|
+
tasks.createChannel,
|
|
56
|
+
tasks.createConnection
|
|
57
|
+
);
|
|
34
58
|
let timer = backoff({});
|
|
35
59
|
let paused = true;
|
|
36
60
|
let shuttingDown = false;
|
|
@@ -41,48 +65,56 @@ function Vhost(config) {
|
|
|
41
65
|
|
|
42
66
|
pauseChannelAllocation();
|
|
43
67
|
|
|
44
|
-
this.init = function(next) {
|
|
68
|
+
this.init = function (next) {
|
|
45
69
|
if (shuttingDown) {
|
|
46
|
-
debug(
|
|
70
|
+
debug("Aborting initialisation. Vhost %s is shutting down.", self.name);
|
|
47
71
|
return next();
|
|
48
72
|
}
|
|
49
73
|
|
|
50
|
-
debug(
|
|
74
|
+
debug("Initialising vhost: %s", self.name);
|
|
51
75
|
pauseChannelAllocation();
|
|
52
76
|
|
|
53
|
-
init(
|
|
54
|
-
|
|
77
|
+
init(
|
|
78
|
+
config,
|
|
79
|
+
{ connectionIndex: self.connectionIndex },
|
|
80
|
+
(err, config, ctx) => {
|
|
81
|
+
if (err) return next(err);
|
|
55
82
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
83
|
+
connection = ctx.connection;
|
|
84
|
+
self.connectionIndex = ctx.connectionIndex;
|
|
85
|
+
connectionConfig = ctx.connectionConfig;
|
|
86
|
+
timer = backoff(ctx.connectionConfig.retry);
|
|
60
87
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
88
|
+
attachErrorHandlers(config);
|
|
89
|
+
forwardRabbitMQConnectionEvents();
|
|
90
|
+
ensureChannelPools();
|
|
91
|
+
resumeChannelAllocation();
|
|
65
92
|
|
|
66
|
-
|
|
93
|
+
debug(
|
|
94
|
+
"vhost: %s was initialised with connection: %s",
|
|
95
|
+
self.name,
|
|
96
|
+
connection._rascal_id
|
|
97
|
+
);
|
|
67
98
|
|
|
68
|
-
|
|
69
|
-
|
|
99
|
+
self.emit("connect");
|
|
100
|
+
self.emit("vhost_initialised", self.getConnectionDetails());
|
|
70
101
|
|
|
71
|
-
|
|
72
|
-
|
|
102
|
+
return next(null, self);
|
|
103
|
+
}
|
|
104
|
+
);
|
|
73
105
|
return self;
|
|
74
106
|
};
|
|
75
107
|
|
|
76
|
-
this.forewarn = function(next) {
|
|
77
|
-
debug(
|
|
108
|
+
this.forewarn = function (next) {
|
|
109
|
+
debug("Forewarning vhost: %s about impending shutdown", self.name);
|
|
78
110
|
pauseChannelAllocation();
|
|
79
111
|
shuttingDown = true;
|
|
80
112
|
channelCreator.resume();
|
|
81
113
|
next();
|
|
82
114
|
};
|
|
83
115
|
|
|
84
|
-
this.shutdown = function(next) {
|
|
85
|
-
debug(
|
|
116
|
+
this.shutdown = function (next) {
|
|
117
|
+
debug("Shutting down vhost: %s", self.name);
|
|
86
118
|
clearTimeout(reconnectTimeout);
|
|
87
119
|
pauseChannelAllocation();
|
|
88
120
|
drainChannelPools((err) => {
|
|
@@ -91,48 +123,57 @@ function Vhost(config) {
|
|
|
91
123
|
});
|
|
92
124
|
};
|
|
93
125
|
|
|
94
|
-
this.nuke = function(next) {
|
|
95
|
-
debug(
|
|
126
|
+
this.nuke = function (next) {
|
|
127
|
+
debug("Nuking vhost: %s", self.name);
|
|
96
128
|
pauseChannelAllocation();
|
|
97
129
|
drainChannelPools((err) => {
|
|
98
130
|
if (err) return next(err);
|
|
99
131
|
nuke(config, { connectionIndex: self.connectionIndex }, (err) => {
|
|
100
132
|
if (err) return next(err);
|
|
101
|
-
debug(
|
|
133
|
+
debug("Finished nuking vhost: %s", self.name);
|
|
102
134
|
setImmediate(next);
|
|
103
135
|
});
|
|
104
136
|
});
|
|
105
137
|
};
|
|
106
138
|
|
|
107
|
-
this.purge = function(next) {
|
|
108
|
-
debug(
|
|
109
|
-
purge(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
139
|
+
this.purge = function (next) {
|
|
140
|
+
debug("Purging vhost: %s", self.name);
|
|
141
|
+
purge(
|
|
142
|
+
config,
|
|
143
|
+
{ purge: true, connectionIndex: self.connectionIndex },
|
|
144
|
+
(err) => {
|
|
145
|
+
if (err) return next(err);
|
|
146
|
+
debug("Finished purging vhost: %s", self.name);
|
|
147
|
+
setImmediate(next);
|
|
148
|
+
}
|
|
149
|
+
);
|
|
114
150
|
};
|
|
115
151
|
|
|
116
|
-
this.bounce = function(next) {
|
|
117
|
-
async.series([
|
|
118
|
-
self.disconnect,
|
|
119
|
-
self.init,
|
|
120
|
-
], next);
|
|
152
|
+
this.bounce = function (next) {
|
|
153
|
+
async.series([self.disconnect, self.init], next);
|
|
121
154
|
};
|
|
122
155
|
|
|
123
|
-
this.connect = function(next) {
|
|
124
|
-
debug(
|
|
125
|
-
connect(
|
|
126
|
-
|
|
127
|
-
|
|
156
|
+
this.connect = function (next) {
|
|
157
|
+
debug("Connecting to vhost: %s", self.name);
|
|
158
|
+
connect(
|
|
159
|
+
config,
|
|
160
|
+
{ connectionIndex: self.connectionIndex },
|
|
161
|
+
(err, config, ctx) => {
|
|
162
|
+
return next(err, ctx.connection);
|
|
163
|
+
}
|
|
164
|
+
);
|
|
128
165
|
};
|
|
129
166
|
|
|
130
|
-
this.disconnect = function(next) {
|
|
131
|
-
debug(
|
|
167
|
+
this.disconnect = function (next) {
|
|
168
|
+
debug("Disconnecting from vhost: %s", self.name);
|
|
132
169
|
if (!connection) return next();
|
|
133
170
|
connection.removeAllListeners();
|
|
134
|
-
connection.on(
|
|
135
|
-
debug(
|
|
171
|
+
connection.on("error", (err) => {
|
|
172
|
+
debug(
|
|
173
|
+
"Error disconnecting from %s. Original error was: %s",
|
|
174
|
+
connectionConfig.loggableUrl,
|
|
175
|
+
err.message
|
|
176
|
+
);
|
|
136
177
|
});
|
|
137
178
|
connection.close((err) => {
|
|
138
179
|
connection = undefined;
|
|
@@ -140,51 +181,73 @@ function Vhost(config) {
|
|
|
140
181
|
});
|
|
141
182
|
};
|
|
142
183
|
|
|
143
|
-
this.getChannel = function(next) {
|
|
184
|
+
this.getChannel = function (next) {
|
|
144
185
|
channelCreator.push({ confirm: false }, next);
|
|
145
|
-
debug(
|
|
186
|
+
debug(
|
|
187
|
+
"Requested channel. Outstanding channel requests: %d",
|
|
188
|
+
channelCreator.length()
|
|
189
|
+
);
|
|
146
190
|
};
|
|
147
191
|
|
|
148
|
-
this.getConfirmChannel = function(next) {
|
|
192
|
+
this.getConfirmChannel = function (next) {
|
|
149
193
|
channelCreator.push({ confirm: true }, next);
|
|
150
|
-
debug(
|
|
194
|
+
debug(
|
|
195
|
+
"Requested confirm channel. Outstanding channel requests: %d",
|
|
196
|
+
channelCreator.length()
|
|
197
|
+
);
|
|
151
198
|
};
|
|
152
199
|
|
|
153
|
-
this.borrowChannel = function(next) {
|
|
154
|
-
if (!regularChannelPool)
|
|
200
|
+
this.borrowChannel = function (next) {
|
|
201
|
+
if (!regularChannelPool)
|
|
202
|
+
return next(
|
|
203
|
+
new Error(
|
|
204
|
+
format(
|
|
205
|
+
"Vhost: %s must be initialised before you can borrow a channel",
|
|
206
|
+
self.name
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
);
|
|
155
210
|
regularChannelPool.borrow(next);
|
|
156
211
|
};
|
|
157
212
|
|
|
158
|
-
this.returnChannel = function(channel) {
|
|
213
|
+
this.returnChannel = function (channel) {
|
|
159
214
|
if (!regularChannelPool) return;
|
|
160
215
|
regularChannelPool.release(channel);
|
|
161
216
|
};
|
|
162
217
|
|
|
163
|
-
this.destroyChannel = function(channel) {
|
|
218
|
+
this.destroyChannel = function (channel) {
|
|
164
219
|
if (!regularChannelPool) return;
|
|
165
220
|
regularChannelPool.destroy(channel);
|
|
166
221
|
};
|
|
167
222
|
|
|
168
|
-
this.borrowConfirmChannel = function(next) {
|
|
169
|
-
if (!confirmChannelPool)
|
|
223
|
+
this.borrowConfirmChannel = function (next) {
|
|
224
|
+
if (!confirmChannelPool)
|
|
225
|
+
return next(
|
|
226
|
+
new Error(
|
|
227
|
+
format(
|
|
228
|
+
"Vhost: %s must be initialised before you can borrow a confirm channel",
|
|
229
|
+
self.name
|
|
230
|
+
)
|
|
231
|
+
)
|
|
232
|
+
);
|
|
170
233
|
confirmChannelPool.borrow(next);
|
|
171
234
|
};
|
|
172
235
|
|
|
173
|
-
this.returnConfirmChannel = function(channel) {
|
|
236
|
+
this.returnConfirmChannel = function (channel) {
|
|
174
237
|
if (!confirmChannelPool) return;
|
|
175
238
|
confirmChannelPool.release(channel);
|
|
176
239
|
};
|
|
177
240
|
|
|
178
|
-
this.destroyConfirmChannel = function(channel) {
|
|
241
|
+
this.destroyConfirmChannel = function (channel) {
|
|
179
242
|
if (!confirmChannelPool) return;
|
|
180
243
|
confirmChannelPool.destroy(channel);
|
|
181
244
|
};
|
|
182
245
|
|
|
183
|
-
this.isPaused = function() {
|
|
246
|
+
this.isPaused = function () {
|
|
184
247
|
return paused;
|
|
185
248
|
};
|
|
186
249
|
|
|
187
|
-
this.getConnectionDetails = function() {
|
|
250
|
+
this.getConnectionDetails = function () {
|
|
188
251
|
return { vhost: self.name, connectionUrl: connectionConfig.loggableUrl };
|
|
189
252
|
};
|
|
190
253
|
|
|
@@ -197,31 +260,51 @@ function Vhost(config) {
|
|
|
197
260
|
const factory = {
|
|
198
261
|
create() {
|
|
199
262
|
return new Promise((resolve, reject) => {
|
|
200
|
-
debug(
|
|
263
|
+
debug("Creating pooled %s channel for vhost: %s", mode, config.name);
|
|
201
264
|
createChannelWhenInitialised(options.confirm, (err, channel) => {
|
|
202
265
|
if (err) return deferRejection(reject, err);
|
|
203
|
-
if (!channel)
|
|
266
|
+
if (!channel)
|
|
267
|
+
return deferRejection(
|
|
268
|
+
reject,
|
|
269
|
+
new Error("Vhost is shutting down")
|
|
270
|
+
);
|
|
204
271
|
const destroyChannel = _.once(() => {
|
|
205
|
-
debug(
|
|
272
|
+
debug(
|
|
273
|
+
"Destroying %s channel: %s for vhost: %s due to error or close event",
|
|
274
|
+
mode,
|
|
275
|
+
channel._rascal_id,
|
|
276
|
+
config.name
|
|
277
|
+
);
|
|
206
278
|
channel._rascal_closed = true;
|
|
207
279
|
if (pool.isBorrowedResource(channel)) {
|
|
208
280
|
pool.destroy(channel).catch((err) => {
|
|
209
|
-
debug(
|
|
281
|
+
debug(
|
|
282
|
+
"Error destroying %s channel: %s for vhost: %s. %s",
|
|
283
|
+
mode,
|
|
284
|
+
channel._rascal_id,
|
|
285
|
+
config.name,
|
|
286
|
+
err.message
|
|
287
|
+
);
|
|
210
288
|
});
|
|
211
289
|
}
|
|
212
290
|
});
|
|
213
|
-
channel.on(
|
|
214
|
-
channel.on(
|
|
291
|
+
channel.on("error", destroyChannel);
|
|
292
|
+
channel.on("close", destroyChannel);
|
|
215
293
|
resolve(channel);
|
|
216
294
|
});
|
|
217
295
|
});
|
|
218
296
|
},
|
|
219
297
|
destroy(channel) {
|
|
220
298
|
return new Promise((resolve, reject) => {
|
|
221
|
-
debug(
|
|
299
|
+
debug(
|
|
300
|
+
"Destroying %s channel: %s for vhost: %s",
|
|
301
|
+
mode,
|
|
302
|
+
channel._rascal_id,
|
|
303
|
+
config.name
|
|
304
|
+
);
|
|
222
305
|
if (channel._rascal_closed) return resolve();
|
|
223
306
|
channel.removeAllListeners();
|
|
224
|
-
channel.on(
|
|
307
|
+
channel.on("error", reject);
|
|
225
308
|
const closeChannelCb = (err) => {
|
|
226
309
|
if (err) return reject(err);
|
|
227
310
|
resolve();
|
|
@@ -232,14 +315,28 @@ function Vhost(config) {
|
|
|
232
315
|
// will never receive a response from the broker, and the callback will never yield.
|
|
233
316
|
const once = _.once(closeChannelCb);
|
|
234
317
|
setTimeoutUnref(() => {
|
|
235
|
-
once(
|
|
318
|
+
once(
|
|
319
|
+
new Error(
|
|
320
|
+
format(
|
|
321
|
+
"Timeout after %dms closing %s channel: %s for vhost: %s",
|
|
322
|
+
options.pool.destroyTimeoutMillis,
|
|
323
|
+
mode,
|
|
324
|
+
channel._rascal_id,
|
|
325
|
+
config.name
|
|
326
|
+
)
|
|
327
|
+
)
|
|
328
|
+
);
|
|
236
329
|
}, 1000);
|
|
237
330
|
channel.close(once);
|
|
238
331
|
});
|
|
239
332
|
},
|
|
240
333
|
validate(channel) {
|
|
241
334
|
return new Promise((resolve) => {
|
|
242
|
-
resolve(
|
|
335
|
+
resolve(
|
|
336
|
+
!channel._rascal_closed &&
|
|
337
|
+
connection &&
|
|
338
|
+
connection.connection === channel.connection
|
|
339
|
+
);
|
|
243
340
|
});
|
|
244
341
|
},
|
|
245
342
|
};
|
|
@@ -267,68 +364,90 @@ function Vhost(config) {
|
|
|
267
364
|
}
|
|
268
365
|
|
|
269
366
|
function borrow(next) {
|
|
270
|
-
debug(
|
|
367
|
+
debug("Requested %s channel. %o", mode, stats());
|
|
271
368
|
if (poolQueue.length() >= options.pool.max) {
|
|
272
369
|
busy = true;
|
|
273
|
-
self.emit(
|
|
370
|
+
self.emit("busy", stats());
|
|
274
371
|
}
|
|
275
372
|
poolQueue.push(null, (err, channel) => {
|
|
276
373
|
if (err) return next(err);
|
|
277
|
-
debug(
|
|
374
|
+
debug("Borrowed %s channel: %s. %o", mode, channel._rascal_id, stats());
|
|
278
375
|
next(null, channel);
|
|
279
376
|
});
|
|
280
377
|
}
|
|
281
378
|
|
|
282
379
|
function release(channel) {
|
|
283
|
-
debug(
|
|
284
|
-
pool
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
380
|
+
debug("Releasing %s channel: %s. %o", mode, channel._rascal_id, stats());
|
|
381
|
+
pool
|
|
382
|
+
.release(channel)
|
|
383
|
+
.catch((err) => {
|
|
384
|
+
debug(
|
|
385
|
+
"Error releasing %s channel: %s. %s",
|
|
386
|
+
mode,
|
|
387
|
+
channel._rascal_id,
|
|
388
|
+
err.message
|
|
389
|
+
);
|
|
390
|
+
})
|
|
391
|
+
.then(() => {
|
|
392
|
+
if (poolQueue.length() > 0 || !busy) return;
|
|
393
|
+
busy = false;
|
|
394
|
+
self.emit("ready", stats());
|
|
395
|
+
});
|
|
291
396
|
}
|
|
292
397
|
|
|
293
398
|
function destroy(channel) {
|
|
294
|
-
debug(
|
|
295
|
-
pool
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
399
|
+
debug("Destroying %s channel: %s. %o", mode, channel._rascal_id, stats());
|
|
400
|
+
pool
|
|
401
|
+
.destroy(channel)
|
|
402
|
+
.catch((err) => {
|
|
403
|
+
debug(
|
|
404
|
+
"Error destroying %s channel: %s. %s",
|
|
405
|
+
mode,
|
|
406
|
+
channel._rascal_id,
|
|
407
|
+
err.message
|
|
408
|
+
);
|
|
409
|
+
})
|
|
410
|
+
.then(() => {
|
|
411
|
+
if (poolQueue.length() > 0 || !busy) return;
|
|
412
|
+
busy = false;
|
|
413
|
+
self.emit("ready", stats());
|
|
414
|
+
});
|
|
302
415
|
}
|
|
303
416
|
|
|
304
417
|
function drain(next) {
|
|
305
|
-
debug(
|
|
306
|
-
pool
|
|
307
|
-
|
|
308
|
-
|
|
418
|
+
debug("Draining %s channel pool. %o", mode, stats());
|
|
419
|
+
pool
|
|
420
|
+
.drain()
|
|
421
|
+
.then(() => {
|
|
422
|
+
return pool.clear().then(() => {
|
|
423
|
+
debug("Drained %s channel pool. %o", mode, stats());
|
|
424
|
+
setImmediate(next);
|
|
425
|
+
});
|
|
426
|
+
})
|
|
427
|
+
.catch((err) => {
|
|
428
|
+
debug("Error draining %s channel pool. %s", mode, err.message);
|
|
309
429
|
setImmediate(next);
|
|
310
430
|
});
|
|
311
|
-
}).catch((err) => {
|
|
312
|
-
debug('Error draining %s channel pool. %s', mode, err.message);
|
|
313
|
-
setImmediate(next);
|
|
314
|
-
});
|
|
315
431
|
}
|
|
316
432
|
|
|
317
|
-
debug(
|
|
433
|
+
debug("Creating %s channel pool %o", mode, options.pool);
|
|
318
434
|
pool = genericPool.createPool(factory, options.pool);
|
|
319
|
-
pool.on(
|
|
320
|
-
debug(
|
|
435
|
+
pool.on("factoryCreateError", (err) => {
|
|
436
|
+
debug("Create error emitted by %s channel pool: %s", mode, err.message);
|
|
321
437
|
});
|
|
322
|
-
pool.on(
|
|
323
|
-
debug(
|
|
438
|
+
pool.on("factoryDestroyError", (err) => {
|
|
439
|
+
debug("Destroy error emitted by %s channel pool: %s", mode, err.message);
|
|
324
440
|
});
|
|
325
441
|
|
|
326
442
|
poolQueue = async.queue((__, next) => {
|
|
327
|
-
pool
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
443
|
+
pool
|
|
444
|
+
.acquire()
|
|
445
|
+
.then((channel) => {
|
|
446
|
+
setImmediate(() => {
|
|
447
|
+
next(null, channel);
|
|
448
|
+
});
|
|
449
|
+
})
|
|
450
|
+
.catch(next);
|
|
332
451
|
}, 1);
|
|
333
452
|
|
|
334
453
|
return {
|
|
@@ -344,37 +463,52 @@ function Vhost(config) {
|
|
|
344
463
|
|
|
345
464
|
function createChannelWhenInitialised(confirm, next) {
|
|
346
465
|
if (connection) return createChannel(confirm, next);
|
|
347
|
-
debug(
|
|
466
|
+
debug(
|
|
467
|
+
"Vhost: %s is not initialised. Deferring channel creation",
|
|
468
|
+
self.name
|
|
469
|
+
);
|
|
348
470
|
setTimeoutUnref(() => {
|
|
349
|
-
self.removeListener(
|
|
350
|
-
next(new Error(
|
|
471
|
+
self.removeListener("vhost_initialised", onVhostInitialised);
|
|
472
|
+
next(new Error("Timedout acquiring channel"), 5000);
|
|
351
473
|
});
|
|
352
474
|
function onVhostInitialised() {
|
|
353
|
-
debug(
|
|
354
|
-
createChannel(confirm, next);
|
|
475
|
+
debug("Vhost: %s was initialised. Resuming channel creation", self.name);
|
|
476
|
+
createChannel(confirm, next);
|
|
355
477
|
}
|
|
356
|
-
self.once(
|
|
478
|
+
self.once("vhost_initialised", onVhostInitialised);
|
|
357
479
|
}
|
|
358
480
|
|
|
359
481
|
function createChannel(confirm, next) {
|
|
360
|
-
|
|
361
482
|
if (shuttingDown) {
|
|
362
|
-
debug(
|
|
483
|
+
debug(
|
|
484
|
+
"Ignoring create channel request. Vhost: %s is shutting down.",
|
|
485
|
+
self.name
|
|
486
|
+
);
|
|
363
487
|
return next();
|
|
364
488
|
}
|
|
365
|
-
if (!connection)
|
|
489
|
+
if (!connection)
|
|
490
|
+
return next(
|
|
491
|
+
new Error(
|
|
492
|
+
format(
|
|
493
|
+
"Vhost: %s must be initialised before you can create a channel",
|
|
494
|
+
self.name
|
|
495
|
+
)
|
|
496
|
+
)
|
|
497
|
+
);
|
|
366
498
|
|
|
367
499
|
// Same problem as https://github.com/guidesmiths/rascal/issues/17
|
|
368
500
|
const once = _.once(next);
|
|
369
501
|
let invocations = 0;
|
|
370
502
|
const channelId = uuid();
|
|
371
503
|
|
|
372
|
-
connection.once(
|
|
373
|
-
connection.once(
|
|
374
|
-
confirm
|
|
504
|
+
connection.once("close", closeHandler);
|
|
505
|
+
connection.once("error", errorHandler);
|
|
506
|
+
confirm
|
|
507
|
+
? connection.createConfirmChannel(callback)
|
|
508
|
+
: connection.createChannel(callback);
|
|
375
509
|
|
|
376
510
|
function closeHandler() {
|
|
377
|
-
once(new Error(
|
|
511
|
+
once(new Error("Connection closed"));
|
|
378
512
|
}
|
|
379
513
|
|
|
380
514
|
function errorHandler(err) {
|
|
@@ -383,20 +517,33 @@ function Vhost(config) {
|
|
|
383
517
|
|
|
384
518
|
function callback(err, channel) {
|
|
385
519
|
invocations++;
|
|
386
|
-
connection && connection.removeListener(
|
|
387
|
-
connection && connection.removeListener(
|
|
520
|
+
connection && connection.removeListener("close", closeHandler);
|
|
521
|
+
connection && connection.removeListener("error", errorHandler);
|
|
388
522
|
if (err) {
|
|
389
|
-
debug(
|
|
523
|
+
debug(
|
|
524
|
+
"Error creating channel: %s from %s: %s",
|
|
525
|
+
channelId,
|
|
526
|
+
connectionConfig.loggableUrl,
|
|
527
|
+
err.message
|
|
528
|
+
);
|
|
390
529
|
return once(err);
|
|
391
530
|
}
|
|
392
531
|
|
|
393
532
|
channel._rascal_id = channelId;
|
|
394
533
|
channel.connection._rascal_id = connection._rascal_id;
|
|
395
|
-
debug(
|
|
534
|
+
debug(
|
|
535
|
+
"Created %s channel: %s from connection: %s",
|
|
536
|
+
getChannelMode(confirm),
|
|
537
|
+
channel._rascal_id,
|
|
538
|
+
connection._rascal_id
|
|
539
|
+
);
|
|
396
540
|
|
|
397
541
|
// See https://github.com/squaremo/amqp.node/issues/388
|
|
398
542
|
if (invocations > 1) {
|
|
399
|
-
debug(
|
|
543
|
+
debug(
|
|
544
|
+
"Closing superfluous channel: %s previously reported as errored",
|
|
545
|
+
channel._rascal_id
|
|
546
|
+
);
|
|
400
547
|
return channel.close();
|
|
401
548
|
}
|
|
402
549
|
|
|
@@ -405,7 +552,7 @@ function Vhost(config) {
|
|
|
405
552
|
}
|
|
406
553
|
|
|
407
554
|
function getChannelMode(confirm) {
|
|
408
|
-
return confirm ?
|
|
555
|
+
return confirm ? "confirm" : "regular";
|
|
409
556
|
}
|
|
410
557
|
|
|
411
558
|
function pauseChannelAllocation() {
|
|
@@ -413,7 +560,7 @@ function Vhost(config) {
|
|
|
413
560
|
regularChannelPool && regularChannelPool.pause();
|
|
414
561
|
confirmChannelPool && confirmChannelPool.pause();
|
|
415
562
|
paused = true;
|
|
416
|
-
self.emit(
|
|
563
|
+
self.emit("paused", { vhost: self.name });
|
|
417
564
|
}
|
|
418
565
|
|
|
419
566
|
function resumeChannelAllocation() {
|
|
@@ -421,52 +568,76 @@ function Vhost(config) {
|
|
|
421
568
|
regularChannelPool && regularChannelPool.resume();
|
|
422
569
|
confirmChannelPool && confirmChannelPool.resume();
|
|
423
570
|
paused = false;
|
|
424
|
-
self.emit(
|
|
571
|
+
self.emit("resumed", { vhost: self.name });
|
|
425
572
|
}
|
|
426
573
|
|
|
427
574
|
function forwardRabbitMQConnectionEvents() {
|
|
428
|
-
connection.on(
|
|
429
|
-
self.emit(
|
|
575
|
+
connection.on("blocked", (reason) => {
|
|
576
|
+
self.emit("blocked", reason, self.getConnectionDetails());
|
|
430
577
|
});
|
|
431
|
-
connection.on(
|
|
432
|
-
self.emit(
|
|
578
|
+
connection.on("unblocked", () => {
|
|
579
|
+
self.emit("unblocked", self.getConnectionDetails());
|
|
433
580
|
});
|
|
434
581
|
}
|
|
435
582
|
|
|
436
583
|
function ensureChannelPools() {
|
|
437
|
-
regularChannelPool =
|
|
438
|
-
|
|
584
|
+
regularChannelPool =
|
|
585
|
+
regularChannelPool ||
|
|
586
|
+
createChannelPool({
|
|
587
|
+
confirm: false,
|
|
588
|
+
pool: config.publicationChannelPools.regularPool,
|
|
589
|
+
});
|
|
590
|
+
confirmChannelPool =
|
|
591
|
+
confirmChannelPool ||
|
|
592
|
+
createChannelPool({
|
|
593
|
+
confirm: true,
|
|
594
|
+
pool: config.publicationChannelPools.confirmPool,
|
|
595
|
+
});
|
|
439
596
|
}
|
|
440
597
|
|
|
441
598
|
function drainChannelPools(next) {
|
|
442
|
-
async.series(
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
599
|
+
async.series(
|
|
600
|
+
[
|
|
601
|
+
function (cb) {
|
|
602
|
+
regularChannelPool ? regularChannelPool.drain(cb) : cb();
|
|
603
|
+
},
|
|
604
|
+
function (cb) {
|
|
605
|
+
confirmChannelPool ? confirmChannelPool.drain(cb) : cb();
|
|
606
|
+
},
|
|
607
|
+
],
|
|
608
|
+
next
|
|
609
|
+
);
|
|
450
610
|
}
|
|
451
611
|
|
|
452
612
|
function attachErrorHandlers(config) {
|
|
453
|
-
connection.removeAllListeners(
|
|
454
|
-
const errorHandler = _.once(
|
|
455
|
-
|
|
456
|
-
|
|
613
|
+
connection.removeAllListeners("error");
|
|
614
|
+
const errorHandler = _.once(
|
|
615
|
+
handleConnectionError.bind(null, connection, config)
|
|
616
|
+
);
|
|
617
|
+
connection.on("error", errorHandler);
|
|
618
|
+
connection.on("close", errorHandler);
|
|
457
619
|
}
|
|
458
620
|
|
|
459
621
|
function handleConnectionError(borked, config, err) {
|
|
460
|
-
debug(
|
|
622
|
+
debug(
|
|
623
|
+
"Handling connection error: %s initially from connection: %s, %s",
|
|
624
|
+
err.message,
|
|
625
|
+
borked._rascal_id,
|
|
626
|
+
connectionConfig.loggableUrl
|
|
627
|
+
);
|
|
461
628
|
pauseChannelAllocation();
|
|
462
629
|
connection = undefined;
|
|
463
|
-
self.emit(
|
|
464
|
-
self.emit(
|
|
465
|
-
connectionConfig.retry &&
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
630
|
+
self.emit("disconnect");
|
|
631
|
+
self.emit("error", err, self.getConnectionDetails());
|
|
632
|
+
connectionConfig.retry &&
|
|
633
|
+
self.init((err) => {
|
|
634
|
+
if (!err) return;
|
|
635
|
+
const delay = timer.next();
|
|
636
|
+
debug("Will attempt reconnection in in %dms", delay);
|
|
637
|
+
reconnectTimeout = setTimeoutUnref(
|
|
638
|
+
handleConnectionError.bind(null, borked, config, err),
|
|
639
|
+
delay
|
|
640
|
+
);
|
|
641
|
+
});
|
|
471
642
|
}
|
|
472
643
|
}
|