@natlibfi/melinda-rest-api-commons 2.3.2-alpha.6 → 2.3.2-alpha.8
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/dist/amqp.js +118 -87
- package/dist/amqp.js.map +1 -1
- package/dist/amqp.spec.js +252 -0
- package/dist/amqp.spec.js.map +1 -0
- package/dist/constants.js +5 -3
- package/dist/constants.js.map +1 -1
- package/dist/helpers/conversion.js +5 -25
- package/dist/helpers/conversion.js.map +1 -1
- package/dist/helpers/conversion.spec.js +1 -7
- package/dist/helpers/conversion.spec.js.map +1 -1
- package/dist/helpers/fix-constants.js +6 -4
- package/dist/helpers/fix-constants.js.map +1 -1
- package/dist/helpers/fix-handle-tempurns.js +19 -27
- package/dist/helpers/fix-handle-tempurns.js.map +1 -1
- package/dist/helpers/fix-strip-f884s.js +12 -16
- package/dist/helpers/fix-strip-f884s.js.map +1 -1
- package/dist/helpers/fix-utils.js +9 -15
- package/dist/helpers/fix-utils.js.map +1 -1
- package/dist/helpers/fix.js +17 -32
- package/dist/helpers/fix.js.map +1 -1
- package/dist/helpers/fix.spec.js +1 -12
- package/dist/helpers/fix.spec.js.map +1 -1
- package/dist/helpers/validation.js +0 -6
- package/dist/helpers/validation.js.map +1 -1
- package/dist/helpers/validation.spec.js +1 -7
- package/dist/helpers/validation.spec.js.map +1 -1
- package/dist/index.js +8 -14
- package/dist/index.js.map +1 -1
- package/dist/mongo.js +38 -87
- package/dist/mongo.js.map +1 -1
- package/dist/mongoLog.js +5 -29
- package/dist/mongoLog.js.map +1 -1
- package/dist/utils.js +33 -35
- package/dist/utils.js.map +1 -1
- package/package.json +5 -4
package/dist/amqp.js
CHANGED
|
@@ -4,32 +4,23 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = _default;
|
|
7
|
-
|
|
8
7
|
var _amqplib = _interopRequireDefault(require("amqplib"));
|
|
9
|
-
|
|
10
8
|
var _marcRecord = require("@natlibfi/marc-record");
|
|
11
|
-
|
|
12
9
|
var _melindaCommons = require("@natlibfi/melinda-commons");
|
|
13
|
-
|
|
14
10
|
var _melindaBackendCommons = require("@natlibfi/melinda-backend-commons");
|
|
15
|
-
|
|
11
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
16
12
|
var _constants = require("./constants");
|
|
17
|
-
|
|
18
|
-
var _utils = require("./utils");
|
|
19
|
-
|
|
20
13
|
var _util = require("util");
|
|
21
|
-
|
|
22
14
|
var _httpStatus = _interopRequireDefault(require("http-status"));
|
|
23
|
-
|
|
15
|
+
var _utils = require("./utils");
|
|
24
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
|
-
|
|
26
17
|
/**
|
|
27
18
|
*
|
|
28
19
|
* @licstart The following is the entire license notice for the JavaScript code in this file.
|
|
29
20
|
*
|
|
30
21
|
* Shared modules for microservices of Melinda rest api batch import system
|
|
31
22
|
*
|
|
32
|
-
* Copyright (C) 2020-
|
|
23
|
+
* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)
|
|
33
24
|
*
|
|
34
25
|
* This file is part of melinda-rest-api-commons
|
|
35
26
|
*
|
|
@@ -50,10 +41,20 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
50
41
|
* for the JavaScript code in this file.
|
|
51
42
|
*
|
|
52
43
|
*/
|
|
53
|
-
|
|
44
|
+
|
|
45
|
+
//import {logError} from './utils';
|
|
46
|
+
|
|
47
|
+
async function _default(AMQP_URL, runHealthCheck = false) {
|
|
48
|
+
const logger = (0, _melindaBackendCommons.createLogger)();
|
|
49
|
+
const debug = (0, _debug.default)('@natlibfi/melinda-rest-api-commons:amqp');
|
|
50
|
+
const debugHC = debug.extend('HC');
|
|
51
|
+
debug(`Creating an AMQP operator to ${AMQP_URL}`);
|
|
54
52
|
const connection = await _amqplib.default.connect(AMQP_URL);
|
|
55
53
|
const channel = await connection.createChannel();
|
|
56
|
-
const
|
|
54
|
+
const healthCheckLoop = runHealthCheck ? healthCheck() : 'Not running health check';
|
|
55
|
+
debug(`Connection: ${connection}`);
|
|
56
|
+
debug(`Channel: ${channel}`);
|
|
57
|
+
debug(`HealthCheckLoop ${healthCheckLoop}`);
|
|
57
58
|
return {
|
|
58
59
|
checkQueue,
|
|
59
60
|
consumeChunk,
|
|
@@ -62,82 +63,108 @@ async function _default(AMQP_URL) {
|
|
|
62
63
|
nackMessages,
|
|
63
64
|
sendToQueue,
|
|
64
65
|
removeQueue,
|
|
65
|
-
messagesToRecords
|
|
66
|
-
|
|
66
|
+
messagesToRecords,
|
|
67
|
+
closeChannel,
|
|
68
|
+
closeConnection
|
|
69
|
+
};
|
|
70
|
+
async function closeChannel() {
|
|
71
|
+
debug(`Closing channel`);
|
|
72
|
+
await channel.close();
|
|
73
|
+
debug(`Channel: ${channel}`);
|
|
74
|
+
}
|
|
75
|
+
async function closeConnection() {
|
|
76
|
+
debug(`Closing connection`);
|
|
77
|
+
await connection.close();
|
|
78
|
+
debug(`Connection: ${connection}`);
|
|
79
|
+
}
|
|
80
|
+
async function healthCheck(wait = false) {
|
|
81
|
+
const setTimeoutPromise = (0, _util.promisify)(setTimeout);
|
|
82
|
+
if (wait) {
|
|
83
|
+
await setTimeoutPromise(wait);
|
|
84
|
+
return healthCheck(false);
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
debugHC(`Health checking amqp by asserting a queue`);
|
|
88
|
+
await channel.assertQueue('HEALTHCHECK', {
|
|
89
|
+
durable: false
|
|
90
|
+
});
|
|
91
|
+
debugHC(`Waiting 200ms before running healthCheck next`);
|
|
92
|
+
return healthCheck('200');
|
|
93
|
+
} catch (error) {
|
|
94
|
+
const errorToThrow = error;
|
|
95
|
+
debugHC(`HealthCheck error ${JSON.stringify(error)}`);
|
|
96
|
+
handleAmqpErrors(errorToThrow);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
67
99
|
|
|
100
|
+
// eslint-disable-next-line max-statements
|
|
68
101
|
async function checkQueue({
|
|
69
102
|
queue,
|
|
70
103
|
style = 'basic',
|
|
71
104
|
toRecord = true,
|
|
72
105
|
purge = false
|
|
73
106
|
}) {
|
|
74
|
-
|
|
75
|
-
|
|
107
|
+
debug(`checkQueue: ${queue}, Style: ${style}, toRecord: ${toRecord}, Purge: ${purge}`);
|
|
76
108
|
try {
|
|
77
109
|
errorUndefinedQueue(queue);
|
|
78
110
|
const channelInfo = await channel.assertQueue(queue, {
|
|
79
111
|
durable: true
|
|
80
112
|
});
|
|
81
|
-
|
|
82
113
|
if (purge) {
|
|
83
114
|
await purgeQueue(purge);
|
|
84
115
|
logger.verbose(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);
|
|
116
|
+
debug(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);
|
|
85
117
|
return checkQueue({
|
|
86
118
|
queue,
|
|
87
119
|
style
|
|
88
120
|
});
|
|
89
121
|
}
|
|
90
|
-
|
|
122
|
+
if (style === 'messages') {
|
|
123
|
+
return channelInfo.messageCount;
|
|
124
|
+
}
|
|
91
125
|
if (channelInfo.messageCount < 1) {
|
|
92
|
-
|
|
126
|
+
debug(`checkQueue: ${channelInfo.messageCount} - ${queue} is empty`);
|
|
93
127
|
return false;
|
|
94
128
|
}
|
|
129
|
+
debug(`Queue ${queue} has ${channelInfo.messageCount} messages`);
|
|
95
130
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (style === 'messages') {
|
|
99
|
-
return channelInfo.messageCount;
|
|
100
|
-
} // Note: returns one message (+ record, of toRecord: true)
|
|
131
|
+
// Note: returns one message (+ record, of toRecord: true)
|
|
101
132
|
// note: if toRecord is false returns just plain message / false
|
|
102
133
|
// note: if toRecord is true returns {headers, records, messages} -object / false
|
|
103
134
|
// should this be more consistent?
|
|
104
|
-
|
|
105
|
-
|
|
106
135
|
if (style === 'one') {
|
|
107
136
|
return consumeOne(queue, toRecord);
|
|
108
|
-
}
|
|
109
|
-
// returns {headers, records, messages} object or {headers, messages} object depending on toRecord
|
|
110
|
-
|
|
137
|
+
}
|
|
111
138
|
|
|
139
|
+
// Note: returns a chunk of (100) messages (+ records, if toRecord: true)
|
|
140
|
+
// returns {headers, records, messages} object or {headers, messages} object depending on toRecord
|
|
112
141
|
if (style === 'basic') {
|
|
113
142
|
return consumeChunk(queue, toRecord);
|
|
114
|
-
}
|
|
115
|
-
|
|
143
|
+
}
|
|
116
144
|
|
|
145
|
+
// Defaults:
|
|
117
146
|
throw new _melindaCommons.Error(_httpStatus.default.UNPROCESSABLE_ENTITY);
|
|
118
147
|
} catch (error) {
|
|
119
|
-
(
|
|
148
|
+
handleAmqpErrors(error);
|
|
120
149
|
}
|
|
121
|
-
|
|
122
150
|
function purgeQueue(purge) {
|
|
151
|
+
debug(`Purging queue: ${queue}, purge: ${purge}`);
|
|
123
152
|
if (purge) {
|
|
124
153
|
return channel.purgeQueue(queue);
|
|
125
154
|
}
|
|
126
155
|
}
|
|
127
156
|
}
|
|
128
|
-
|
|
129
157
|
async function consumeChunk(queue, toRecord) {
|
|
130
|
-
|
|
131
|
-
|
|
158
|
+
debug(`Prepared to consumeChunk from queue: ${queue}`);
|
|
132
159
|
try {
|
|
133
160
|
await channel.assertQueue(queue, {
|
|
134
161
|
durable: true
|
|
135
|
-
});
|
|
162
|
+
});
|
|
136
163
|
|
|
164
|
+
// getData: next chunk (100) messages
|
|
137
165
|
const messages = await getData(queue);
|
|
138
166
|
const headers = getHeaderInfo(messages[0]);
|
|
139
|
-
|
|
140
|
-
|
|
167
|
+
debug(`consumeChunk (${messages ? messages.length : '0'} from queue ${queue}) ${toRecord ? 'to records' : 'just messages'}`);
|
|
141
168
|
if (toRecord) {
|
|
142
169
|
const records = await messagesToRecords(messages);
|
|
143
170
|
return {
|
|
@@ -146,33 +173,30 @@ async function _default(AMQP_URL) {
|
|
|
146
173
|
messages
|
|
147
174
|
};
|
|
148
175
|
}
|
|
149
|
-
|
|
150
176
|
return {
|
|
151
177
|
headers,
|
|
152
178
|
messages
|
|
153
179
|
};
|
|
154
180
|
} catch (error) {
|
|
155
|
-
(
|
|
181
|
+
handleAmqpErrors(error);
|
|
156
182
|
}
|
|
157
183
|
}
|
|
158
|
-
|
|
159
184
|
async function consumeOne(queue, toRecord) {
|
|
160
|
-
|
|
161
|
-
|
|
185
|
+
debug(`Prepared to consumeOne from queue: ${queue}`);
|
|
162
186
|
try {
|
|
163
187
|
await channel.assertQueue(queue, {
|
|
164
188
|
durable: true
|
|
165
|
-
});
|
|
189
|
+
});
|
|
166
190
|
|
|
191
|
+
// Returns false if 0 items in queue
|
|
167
192
|
const message = await channel.get(queue);
|
|
168
|
-
|
|
193
|
+
debug(`Message: ${(0, _util.inspect)(message, {
|
|
169
194
|
colors: true,
|
|
170
195
|
maxArrayLength: 3,
|
|
171
196
|
depth: 3
|
|
172
|
-
})}`);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
197
|
+
})}`);
|
|
198
|
+
// Do not spam the logs
|
|
199
|
+
debug(`consumeOne from queue: ${queue} ${toRecord ? 'to records' : 'just the message'}`);
|
|
176
200
|
if (message) {
|
|
177
201
|
if (toRecord) {
|
|
178
202
|
const headers = getHeaderInfo(message);
|
|
@@ -183,127 +207,134 @@ async function _default(AMQP_URL) {
|
|
|
183
207
|
messages: [message]
|
|
184
208
|
};
|
|
185
209
|
}
|
|
186
|
-
|
|
187
210
|
return message;
|
|
188
211
|
}
|
|
189
|
-
|
|
190
212
|
return false;
|
|
191
213
|
} catch (error) {
|
|
192
|
-
(
|
|
214
|
+
handleAmqpErrors(error);
|
|
193
215
|
}
|
|
194
216
|
}
|
|
195
|
-
|
|
196
217
|
function ackMessages(messages) {
|
|
197
218
|
messages.forEach(message => {
|
|
198
|
-
|
|
219
|
+
debug(`Ack message ${message.properties.correlationId}`);
|
|
199
220
|
channel.ack(message);
|
|
200
221
|
});
|
|
201
222
|
}
|
|
202
|
-
|
|
203
223
|
function nackMessages(messages) {
|
|
204
224
|
messages.forEach(message => {
|
|
205
|
-
|
|
225
|
+
debug(`Nack message ${message.properties.correlationId}`);
|
|
206
226
|
channel.nack(message);
|
|
207
227
|
});
|
|
208
228
|
}
|
|
209
|
-
|
|
210
229
|
async function sendToQueue({
|
|
211
230
|
queue,
|
|
212
231
|
correlationId,
|
|
213
232
|
headers,
|
|
214
233
|
data
|
|
215
234
|
}) {
|
|
235
|
+
debug(`sendToQueue`);
|
|
236
|
+
// eslint-disable-next-line no-useless-catch
|
|
216
237
|
try {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
238
|
+
debug(`Queue ${queue}`);
|
|
239
|
+
debug(`CorrelationId ${correlationId}`);
|
|
240
|
+
debug(`Data ${JSON.stringify(data)}`);
|
|
241
|
+
debug(`Headers ${JSON.stringify(headers)}`);
|
|
221
242
|
errorUndefinedQueue(queue);
|
|
243
|
+
debug(`Asserting queue: ${queue}`);
|
|
222
244
|
await channel.assertQueue(queue, {
|
|
223
245
|
durable: true
|
|
224
246
|
});
|
|
225
|
-
|
|
247
|
+
debug(`Actually sendToQueue: ${queue}`);
|
|
248
|
+
await channel.sendToQueue(queue, Buffer.from(JSON.stringify({
|
|
226
249
|
data
|
|
227
250
|
})), {
|
|
228
251
|
correlationId,
|
|
229
252
|
persistent: true,
|
|
230
253
|
headers
|
|
231
254
|
});
|
|
232
|
-
|
|
255
|
+
debug(`Send message for ${correlationId} to queue: ${queue}`);
|
|
233
256
|
} catch (error) {
|
|
234
|
-
|
|
257
|
+
const errorToThrow = error;
|
|
258
|
+
//if (error instanceof ApiError) {
|
|
259
|
+
// throw error;
|
|
260
|
+
//}
|
|
261
|
+
debug(`SendToQueue errored: ${JSON.stringify(error)}`);
|
|
262
|
+
handleAmqpErrors(errorToThrow);
|
|
235
263
|
}
|
|
236
264
|
}
|
|
237
|
-
|
|
238
265
|
async function removeQueue(queue) {
|
|
239
266
|
// deleteQueue borks the channel if the queue does not exist
|
|
240
267
|
// -> use throwaway tempChannel to avoid killing actual channel in use
|
|
241
268
|
// this might be doable also with assertQueue before deleteQueue
|
|
242
269
|
const tempChannel = await connection.createChannel();
|
|
243
270
|
logger.verbose(`Removing queue ${queue}.`);
|
|
271
|
+
debug(`Removing queue ${queue}.`);
|
|
244
272
|
await tempChannel.deleteQueue(queue);
|
|
245
|
-
|
|
246
273
|
if (tempChannel) {
|
|
247
|
-
// eslint-disable-line functional/no-conditional-statement
|
|
248
274
|
await tempChannel.close();
|
|
275
|
+
return;
|
|
249
276
|
}
|
|
250
|
-
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ----------------
|
|
251
281
|
// Helper functions
|
|
252
282
|
// ----------------
|
|
253
283
|
|
|
254
|
-
|
|
255
284
|
function messagesToRecords(messages) {
|
|
256
|
-
|
|
285
|
+
debug(`Parsing messages (${messages.length}) to records`);
|
|
257
286
|
return messages.map(message => {
|
|
258
287
|
const content = JSON.parse(message.content.toString());
|
|
259
288
|
return new _marcRecord.MarcRecord(content.data);
|
|
260
289
|
});
|
|
261
290
|
}
|
|
262
|
-
|
|
263
291
|
async function getData(queue) {
|
|
264
|
-
|
|
265
|
-
|
|
292
|
+
debug(`Getting queue data from ${queue}`);
|
|
266
293
|
try {
|
|
267
294
|
const {
|
|
268
295
|
messageCount
|
|
269
296
|
} = await channel.checkQueue(queue);
|
|
270
|
-
|
|
297
|
+
debug(`There is ${messageCount} messages in queue ${queue}`);
|
|
271
298
|
const messagesToGet = messageCount >= _constants.CHUNK_SIZE ? _constants.CHUNK_SIZE : messageCount;
|
|
272
|
-
|
|
299
|
+
debug(`Getting ${messagesToGet} messages from queue ${queue}`);
|
|
273
300
|
const messages = await pump(messagesToGet);
|
|
274
|
-
|
|
301
|
+
debug(`Returning ${messages.length} unique messages`);
|
|
275
302
|
return messages;
|
|
276
303
|
} catch (error) {
|
|
277
|
-
(
|
|
304
|
+
handleAmqpErrors(error);
|
|
278
305
|
}
|
|
279
|
-
|
|
280
306
|
async function pump(count, results = [], identifiers = []) {
|
|
281
307
|
if (count === 0) {
|
|
282
308
|
return results;
|
|
283
309
|
}
|
|
284
|
-
|
|
285
310
|
const message = await channel.get(queue);
|
|
286
311
|
const identifier = {
|
|
287
312
|
correlationId: message.properties.correlationId,
|
|
288
313
|
deliveryTag: message.fields.deliveryTag
|
|
289
|
-
};
|
|
290
|
-
|
|
314
|
+
};
|
|
315
|
+
// Filter not unique messages
|
|
291
316
|
if (identifiers.includes(identifier)) {
|
|
292
317
|
return pump(count - 1, results, identifiers);
|
|
293
318
|
}
|
|
294
|
-
|
|
295
319
|
return pump(count - 1, results.concat(message), identifiers.concat(identifier));
|
|
296
320
|
}
|
|
297
321
|
}
|
|
298
|
-
|
|
299
322
|
function getHeaderInfo(data) {
|
|
300
323
|
return data.properties.headers;
|
|
301
324
|
}
|
|
302
|
-
|
|
303
325
|
function errorUndefinedQueue(queue) {
|
|
304
326
|
if (queue === undefined || queue === '' || queue === null) {
|
|
305
327
|
throw new _melindaCommons.Error(_httpStatus.default.INTERNAL_SERVER_ERROR, `Undefined queue!`);
|
|
306
328
|
}
|
|
307
329
|
}
|
|
330
|
+
function handleAmqpErrors(error) {
|
|
331
|
+
const newError = error;
|
|
332
|
+
//debug(`HandleAmqpErrors got an error: ${JSON.stringify(error)}`);
|
|
333
|
+
if (error instanceof _melindaCommons.Error) {
|
|
334
|
+
throw new _melindaCommons.Error(newError.status, newError.payload);
|
|
335
|
+
}
|
|
336
|
+
(0, _utils.logError)(error);
|
|
337
|
+
throw newError;
|
|
338
|
+
}
|
|
308
339
|
}
|
|
309
340
|
//# sourceMappingURL=amqp.js.map
|
package/dist/amqp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amqp.js","names":["AMQP_URL","connection","amqplib","connect","channel","createChannel","logger","createLogger","checkQueue","consumeChunk","consumeOne","ackMessages","nackMessages","sendToQueue","removeQueue","messagesToRecords","queue","style","toRecord","purge","silly","errorUndefinedQueue","channelInfo","assertQueue","durable","purgeQueue","verbose","messageCount","ApiError","httpStatus","UNPROCESSABLE_ENTITY","error","logError","messages","getData","headers","getHeaderInfo","debug","length","records","message","get","inspect","colors","maxArrayLength","depth","forEach","properties","correlationId","ack","nack","data","JSON","stringify","Buffer","from","persistent","tempChannel","deleteQueue","close","map","content","parse","toString","MarcRecord","messagesToGet","CHUNK_SIZE","pump","count","results","identifiers","identifier","deliveryTag","fields","includes","concat","undefined","INTERNAL_SERVER_ERROR"],"sources":["../src/amqp.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Shared modules for microservices of Melinda rest api batch import system\n*\n* Copyright (C) 2020-2021 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-rest-api-commons\n*\n* melinda-rest-api-commons program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Affero General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-rest-api-commons is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Affero General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport amqplib from 'amqplib';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {Error as ApiError} from '@natlibfi/melinda-commons';\nimport {createLogger} from '@natlibfi/melinda-backend-commons';\nimport {CHUNK_SIZE} from './constants';\nimport {logError} from './utils';\nimport {inspect} from 'util';\nimport httpStatus from 'http-status';\n\nexport default async function (AMQP_URL) {\n const connection = await amqplib.connect(AMQP_URL);\n const channel = await connection.createChannel();\n const logger = createLogger();\n\n return {checkQueue, consumeChunk, consumeOne, ackMessages, nackMessages, sendToQueue, removeQueue, messagesToRecords};\n\n // eslint-disable-next-line max-statements\n async function checkQueue({queue, style = 'basic', toRecord = true, purge = false}) {\n logger.silly(`checkQueue: ${queue}, Style: ${style}: toRecord: ${toRecord}, Purge: ${purge}`);\n\n try {\n\n errorUndefinedQueue(queue);\n const channelInfo = await channel.assertQueue(queue, {durable: true});\n\n if (purge) {\n await purgeQueue(purge);\n logger.verbose(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);\n return checkQueue({queue, style});\n }\n\n if (channelInfo.messageCount < 1) {\n logger.silly(`checkQueue: ${channelInfo.messageCount} - ${queue} is empty`);\n return false;\n }\n logger.silly(`Queue ${queue} has ${channelInfo.messageCount} messages`);\n\n if (style === 'messages') {\n return channelInfo.messageCount;\n }\n\n // Note: returns one message (+ record, of toRecord: true)\n // note: if toRecord is false returns just plain message / false\n // note: if toRecord is true returns {headers, records, messages} -object / false\n // should this be more consistent?\n if (style === 'one') {\n return consumeOne(queue, toRecord);\n }\n\n // Note: returns a chunk of (100) messages (+ records, if toRecord: true)\n // returns {headers, records, messages} object or {headers, messages} object depending on toRecord\n if (style === 'basic') {\n return consumeChunk(queue, toRecord);\n }\n\n // Defaults:\n throw new ApiError(httpStatus.UNPROCESSABLE_ENTITY);\n } catch (error) {\n logError(error);\n }\n\n function purgeQueue(purge) {\n if (purge) {\n return channel.purgeQueue(queue);\n }\n }\n }\n\n async function consumeChunk(queue, toRecord) {\n logger.silly(`Prepared to consumeChunk from queue: ${queue}`);\n try {\n await channel.assertQueue(queue, {durable: true});\n\n // getData: next chunk (100) messages\n const messages = await getData(queue);\n const headers = getHeaderInfo(messages[0]);\n logger.debug(`consumeChunk (${messages ? messages.length : '0'} from queue ${queue}) ${toRecord ? 'to records' : 'just messages'}`);\n\n if (toRecord) {\n const records = await messagesToRecords(messages);\n return {headers, records, messages};\n }\n\n return {headers, messages};\n } catch (error) {\n logError(error);\n }\n }\n\n async function consumeOne(queue, toRecord) {\n logger.silly(`Prepared to consumeOne from queue: ${queue}`);\n try {\n await channel.assertQueue(queue, {durable: true});\n\n // Returns false if 0 items in queue\n const message = await channel.get(queue);\n\n logger.silly(`Message: ${inspect(message, {colors: true, maxArrayLength: 3, depth: 3})}`);\n // Do not spam the logs\n logger.debug(`consumeOne from queue: ${queue} ${toRecord ? 'to records' : 'just the message'}`);\n\n if (message) {\n if (toRecord) {\n const headers = getHeaderInfo(message);\n const records = messagesToRecords([message]);\n return {headers, records, messages: [message]};\n }\n\n return message;\n }\n\n return false;\n } catch (error) {\n logError(error);\n }\n }\n\n function ackMessages(messages) {\n messages.forEach(message => {\n logger.silly(`Ack message ${message.properties.correlationId}`);\n channel.ack(message);\n });\n }\n\n function nackMessages(messages) {\n messages.forEach(message => {\n logger.silly(`Nack message ${message.properties.correlationId}`);\n channel.nack(message);\n });\n }\n\n async function sendToQueue({queue, correlationId, headers, data}) {\n try {\n logger.silly(`Queue ${queue}`);\n logger.silly(`CorrelationId ${correlationId}`);\n logger.silly(`Data ${JSON.stringify(data)}`);\n logger.silly(`Headers ${JSON.stringify(headers)}`);\n\n errorUndefinedQueue(queue);\n await channel.assertQueue(queue, {durable: true});\n\n channel.sendToQueue(\n queue,\n Buffer.from(JSON.stringify({data})),\n {\n correlationId,\n persistent: true,\n headers\n }\n );\n logger.silly(`Send message for ${correlationId} to queue: ${queue}`);\n } catch (error) {\n logError(error);\n }\n }\n\n async function removeQueue(queue) {\n // deleteQueue borks the channel if the queue does not exist\n // -> use throwaway tempChannel to avoid killing actual channel in use\n // this might be doable also with assertQueue before deleteQueue\n const tempChannel = await connection.createChannel();\n logger.verbose(`Removing queue ${queue}.`);\n await tempChannel.deleteQueue(queue);\n if (tempChannel) { // eslint-disable-line functional/no-conditional-statement\n await tempChannel.close();\n }\n }\n\n // ----------------\n // Helper functions\n // ----------------\n\n function messagesToRecords(messages) {\n logger.debug(`Parsing messages (${messages.length}) to records`);\n\n return messages.map(message => {\n const content = JSON.parse(message.content.toString());\n return new MarcRecord(content.data);\n });\n }\n\n async function getData(queue) {\n logger.debug(`Getting queue data from ${queue}`);\n try {\n const {messageCount} = await channel.checkQueue(queue);\n logger.silly(`There is ${messageCount} messages in queue ${queue}`);\n const messagesToGet = messageCount >= CHUNK_SIZE ? CHUNK_SIZE : messageCount;\n logger.silly(`Getting ${messagesToGet} messages from queue ${queue}`);\n\n const messages = await pump(messagesToGet);\n\n logger.debug(`Returning ${messages.length} unique messages`);\n\n return messages;\n } catch (error) {\n logError(error);\n }\n\n async function pump(count, results = [], identifiers = []) {\n if (count === 0) {\n return results;\n }\n\n const message = await channel.get(queue);\n const identifier = {\n correlationId: message.properties.correlationId,\n deliveryTag: message.fields.deliveryTag\n };\n // Filter not unique messages\n if (identifiers.includes(identifier)) {\n return pump(count - 1, results, identifiers);\n }\n\n return pump(count - 1, results.concat(message), identifiers.concat(identifier));\n }\n }\n\n function getHeaderInfo(data) {\n return data.properties.headers;\n }\n\n function errorUndefinedQueue(queue) {\n if (queue === undefined || queue === '' || queue === null) {\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Undefined queue!`);\n }\n }\n}\n\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"amqp.js","names":["AMQP_URL","runHealthCheck","logger","createLogger","debug","createDebugLogger","debugHC","extend","connection","amqplib","connect","channel","createChannel","healthCheckLoop","healthCheck","checkQueue","consumeChunk","consumeOne","ackMessages","nackMessages","sendToQueue","removeQueue","messagesToRecords","closeChannel","closeConnection","close","wait","setTimeoutPromise","promisify","setTimeout","assertQueue","durable","error","errorToThrow","JSON","stringify","handleAmqpErrors","queue","style","toRecord","purge","errorUndefinedQueue","channelInfo","purgeQueue","verbose","messageCount","ApiError","httpStatus","UNPROCESSABLE_ENTITY","messages","getData","headers","getHeaderInfo","length","records","message","get","inspect","colors","maxArrayLength","depth","forEach","properties","correlationId","ack","nack","data","Buffer","from","persistent","tempChannel","deleteQueue","map","content","parse","toString","MarcRecord","messagesToGet","CHUNK_SIZE","pump","count","results","identifiers","identifier","deliveryTag","fields","includes","concat","undefined","INTERNAL_SERVER_ERROR","newError","status","payload","logError"],"sources":["../src/amqp.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Shared modules for microservices of Melinda rest api batch import system\n*\n* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-rest-api-commons\n*\n* melinda-rest-api-commons program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Affero General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-rest-api-commons is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Affero General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport amqplib from 'amqplib';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {Error as ApiError} from '@natlibfi/melinda-commons';\nimport {createLogger} from '@natlibfi/melinda-backend-commons';\nimport createDebugLogger from 'debug';\nimport {CHUNK_SIZE} from './constants';\n//import {logError} from './utils';\nimport {promisify, inspect} from 'util';\nimport httpStatus from 'http-status';\nimport {logError} from './utils';\n\nexport default async function (AMQP_URL, runHealthCheck = false) {\n const logger = createLogger();\n const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons:amqp');\n const debugHC = debug.extend('HC');\n\n debug(`Creating an AMQP operator to ${AMQP_URL}`);\n const connection = await amqplib.connect(AMQP_URL);\n const channel = await connection.createChannel();\n\n const healthCheckLoop = runHealthCheck ? healthCheck() : 'Not running health check';\n\n debug(`Connection: ${connection}`);\n debug(`Channel: ${channel}`);\n debug(`HealthCheckLoop ${healthCheckLoop}`);\n\n return {checkQueue, consumeChunk, consumeOne, ackMessages, nackMessages, sendToQueue, removeQueue, messagesToRecords, closeChannel, closeConnection};\n\n async function closeChannel() {\n debug(`Closing channel`);\n await channel.close();\n debug(`Channel: ${channel}`);\n }\n\n async function closeConnection() {\n debug(`Closing connection`);\n await connection.close();\n debug(`Connection: ${connection}`);\n }\n\n async function healthCheck(wait = false) {\n const setTimeoutPromise = promisify(setTimeout);\n if (wait) {\n await setTimeoutPromise(wait);\n return healthCheck(false);\n }\n\n try {\n debugHC(`Health checking amqp by asserting a queue`);\n await channel.assertQueue('HEALTHCHECK', {durable: false});\n debugHC(`Waiting 200ms before running healthCheck next`);\n return healthCheck('200');\n } catch (error) {\n const errorToThrow = error;\n debugHC(`HealthCheck error ${JSON.stringify(error)}`);\n handleAmqpErrors(errorToThrow);\n }\n }\n\n // eslint-disable-next-line max-statements\n async function checkQueue({queue, style = 'basic', toRecord = true, purge = false}) {\n debug(`checkQueue: ${queue}, Style: ${style}, toRecord: ${toRecord}, Purge: ${purge}`);\n\n try {\n\n errorUndefinedQueue(queue);\n const channelInfo = await channel.assertQueue(queue, {durable: true});\n\n if (purge) {\n await purgeQueue(purge);\n logger.verbose(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);\n debug(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);\n return checkQueue({queue, style});\n }\n\n if (style === 'messages') {\n return channelInfo.messageCount;\n }\n\n if (channelInfo.messageCount < 1) {\n debug(`checkQueue: ${channelInfo.messageCount} - ${queue} is empty`);\n return false;\n }\n debug(`Queue ${queue} has ${channelInfo.messageCount} messages`);\n\n // Note: returns one message (+ record, of toRecord: true)\n // note: if toRecord is false returns just plain message / false\n // note: if toRecord is true returns {headers, records, messages} -object / false\n // should this be more consistent?\n if (style === 'one') {\n return consumeOne(queue, toRecord);\n }\n\n // Note: returns a chunk of (100) messages (+ records, if toRecord: true)\n // returns {headers, records, messages} object or {headers, messages} object depending on toRecord\n if (style === 'basic') {\n return consumeChunk(queue, toRecord);\n }\n\n // Defaults:\n throw new ApiError(httpStatus.UNPROCESSABLE_ENTITY);\n } catch (error) {\n handleAmqpErrors(error);\n }\n\n function purgeQueue(purge) {\n debug(`Purging queue: ${queue}, purge: ${purge}`);\n if (purge) {\n return channel.purgeQueue(queue);\n }\n }\n }\n\n async function consumeChunk(queue, toRecord) {\n debug(`Prepared to consumeChunk from queue: ${queue}`);\n try {\n await channel.assertQueue(queue, {durable: true});\n\n // getData: next chunk (100) messages\n const messages = await getData(queue);\n const headers = getHeaderInfo(messages[0]);\n debug(`consumeChunk (${messages ? messages.length : '0'} from queue ${queue}) ${toRecord ? 'to records' : 'just messages'}`);\n\n if (toRecord) {\n const records = await messagesToRecords(messages);\n return {headers, records, messages};\n }\n\n return {headers, messages};\n } catch (error) {\n handleAmqpErrors(error);\n }\n }\n\n async function consumeOne(queue, toRecord) {\n debug(`Prepared to consumeOne from queue: ${queue}`);\n try {\n await channel.assertQueue(queue, {durable: true});\n\n // Returns false if 0 items in queue\n const message = await channel.get(queue);\n\n debug(`Message: ${inspect(message, {colors: true, maxArrayLength: 3, depth: 3})}`);\n // Do not spam the logs\n debug(`consumeOne from queue: ${queue} ${toRecord ? 'to records' : 'just the message'}`);\n\n if (message) {\n if (toRecord) {\n const headers = getHeaderInfo(message);\n const records = messagesToRecords([message]);\n return {headers, records, messages: [message]};\n }\n\n return message;\n }\n\n return false;\n } catch (error) {\n handleAmqpErrors(error);\n }\n }\n\n function ackMessages(messages) {\n messages.forEach(message => {\n debug(`Ack message ${message.properties.correlationId}`);\n channel.ack(message);\n });\n }\n\n function nackMessages(messages) {\n messages.forEach(message => {\n debug(`Nack message ${message.properties.correlationId}`);\n channel.nack(message);\n });\n }\n\n async function sendToQueue({queue, correlationId, headers, data}) {\n debug(`sendToQueue`);\n // eslint-disable-next-line no-useless-catch\n try {\n debug(`Queue ${queue}`);\n debug(`CorrelationId ${correlationId}`);\n debug(`Data ${JSON.stringify(data)}`);\n debug(`Headers ${JSON.stringify(headers)}`);\n\n errorUndefinedQueue(queue);\n\n debug(`Asserting queue: ${queue}`);\n await channel.assertQueue(queue, {durable: true});\n\n debug(`Actually sendToQueue: ${queue}`);\n await channel.sendToQueue(\n queue,\n Buffer.from(JSON.stringify({data})),\n {\n correlationId,\n persistent: true,\n headers\n }\n );\n debug(`Send message for ${correlationId} to queue: ${queue}`);\n\n\n } catch (error) {\n const errorToThrow = error;\n //if (error instanceof ApiError) {\n // throw error;\n //}\n debug(`SendToQueue errored: ${JSON.stringify(error)}`);\n handleAmqpErrors(errorToThrow);\n }\n }\n\n async function removeQueue(queue) {\n // deleteQueue borks the channel if the queue does not exist\n // -> use throwaway tempChannel to avoid killing actual channel in use\n // this might be doable also with assertQueue before deleteQueue\n const tempChannel = await connection.createChannel();\n logger.verbose(`Removing queue ${queue}.`);\n debug(`Removing queue ${queue}.`);\n await tempChannel.deleteQueue(queue);\n\n if (tempChannel) {\n await tempChannel.close();\n return;\n }\n\n return;\n }\n\n // ----------------\n // Helper functions\n // ----------------\n\n function messagesToRecords(messages) {\n debug(`Parsing messages (${messages.length}) to records`);\n\n return messages.map(message => {\n const content = JSON.parse(message.content.toString());\n return new MarcRecord(content.data);\n });\n }\n\n async function getData(queue) {\n debug(`Getting queue data from ${queue}`);\n try {\n const {messageCount} = await channel.checkQueue(queue);\n debug(`There is ${messageCount} messages in queue ${queue}`);\n const messagesToGet = messageCount >= CHUNK_SIZE ? CHUNK_SIZE : messageCount;\n debug(`Getting ${messagesToGet} messages from queue ${queue}`);\n\n const messages = await pump(messagesToGet);\n\n debug(`Returning ${messages.length} unique messages`);\n\n return messages;\n } catch (error) {\n handleAmqpErrors(error);\n }\n\n async function pump(count, results = [], identifiers = []) {\n if (count === 0) {\n return results;\n }\n\n const message = await channel.get(queue);\n const identifier = {\n correlationId: message.properties.correlationId,\n deliveryTag: message.fields.deliveryTag\n };\n // Filter not unique messages\n if (identifiers.includes(identifier)) {\n return pump(count - 1, results, identifiers);\n }\n\n return pump(count - 1, results.concat(message), identifiers.concat(identifier));\n }\n }\n\n function getHeaderInfo(data) {\n return data.properties.headers;\n }\n\n function errorUndefinedQueue(queue) {\n if (queue === undefined || queue === '' || queue === null) {\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Undefined queue!`);\n }\n }\n\n function handleAmqpErrors(error) {\n const newError = error;\n //debug(`HandleAmqpErrors got an error: ${JSON.stringify(error)}`);\n if (error instanceof ApiError) {\n throw new ApiError(newError.status, newError.payload);\n }\n logError(error);\n throw newError;\n }\n}\n\n\n"],"mappings":"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"}
|