@natlibfi/melinda-rest-api-commons 6.0.1-alpha.1 → 6.1.0-alpha.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/README.md +34 -0
- package/dist/amqp.js +37 -15
- package/dist/amqp.js.map +2 -2
- package/dist/helpers/conversion.js +1 -2
- package/dist/helpers/conversion.js.map +2 -2
- package/dist/helpers/fix-strip-f884s.js +18 -4
- package/dist/helpers/fix-strip-f884s.js.map +2 -2
- package/dist/helpers/fix.js +12 -8
- package/dist/helpers/fix.js.map +2 -2
- package/dist/helpers/validation.js +1 -1
- package/dist/helpers/validation.js.map +1 -1
- package/dist/mongo.js +200 -109
- package/dist/mongo.js.map +3 -3
- package/dist/mongoLog.js +113 -35
- package/dist/mongoLog.js.map +3 -3
- package/dist/utils.js +33 -4
- package/dist/utils.js.map +2 -2
- package/package.json +11 -17
- package/tests/amqp-error-branches.test.js +535 -0
- package/tests/amqp.healthtest.js +12 -4
- package/tests/amqp.tests.localtest.js +13 -18
- package/tests/helpers/conversion.test.js +16 -0
- package/tests/helpers/fix-edge.test.js +197 -0
- package/tests/helpers/fix.test.js +20 -2
- package/tests/helpers/validation.test.js +6 -2
- package/tests/mongo-check-and-check-state.test.js +3 -1
- package/tests/mongo-check-and-set-import-job-state.test.js +3 -1
- package/tests/mongo-error-branches.test.js +787 -0
- package/tests/mongo-get-stream.test.js +4 -1
- package/tests/mongo-read-content.test.js +10 -0
- package/tests/mongoLog-protect.test.js +181 -0
- package/tests/mongoLog.test.js +113 -6
- package/tests/utils.test.js +360 -0
package/dist/mongo.js
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
import { MongoClient, GridFSBucket, MongoDriverError } from "mongodb";
|
|
2
|
-
import moment from "moment";
|
|
3
2
|
import httpStatus from "http-status";
|
|
4
|
-
import sanitize from "mongo-sanitize";
|
|
5
3
|
import createDebugLogger from "debug";
|
|
6
|
-
import { createLogger } from "@natlibfi/melinda-
|
|
7
|
-
import { Error as ApiError, parseBoolean } from "@natlibfi/melinda-commons";
|
|
4
|
+
import { createLogger, Error as ApiError, parseBoolean } from "@natlibfi/melinda-commons";
|
|
8
5
|
import { QUEUE_ITEM_STATE, IMPORT_JOB_STATE, OPERATIONS } from "./constants.js";
|
|
9
|
-
import { logError } from "./utils.js";
|
|
10
|
-
export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
6
|
+
import { logError, assertString, assertNumber, assertImportJobStateFilter } from "./utils.js";
|
|
7
|
+
export default async function(MONGO_URI, collection, db = "rest-api", deps = {}) {
|
|
11
8
|
const logger = createLogger();
|
|
9
|
+
const timeoutMinutes = Number.parseInt(process.env.MONGO_TIMEOUT_MINUTES, 10) || 1;
|
|
10
|
+
logger.debug(`checkTimeOut window: ${timeoutMinutes} minute(s) (override with MONGO_TIMEOUT_MINUTES)`);
|
|
12
11
|
const debug = createDebugLogger("@natlibfi/melinda-rest-api-commons/mongo");
|
|
13
12
|
const debugDev = debug.extend(":dev");
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
const stubbed = Boolean(deps.operator) && Boolean(deps.gridFSBucket);
|
|
14
|
+
let gridFSBucket = deps.gridFSBucket;
|
|
15
|
+
let operator = deps.operator;
|
|
16
|
+
if (!stubbed) {
|
|
17
|
+
const client = await MongoClient.connect(MONGO_URI);
|
|
18
|
+
const realDb = client.db(db);
|
|
19
|
+
gridFSBucket = gridFSBucket ?? new GridFSBucket(realDb, { bucketName: collection });
|
|
20
|
+
operator = operator ?? realDb.collection(collection);
|
|
21
|
+
}
|
|
18
22
|
debugDev(`mongo: ${MONGO_URI}, db: ${db}, collection: ${collection}`);
|
|
19
23
|
return { createPrio, createBulk, checkAndSetState, checkAndSetImportJobState, query, createProjection, queryById, checkTimeOut, remove, readContent, removeContent, getOne, getStream, setState, setImportJobState, pushIds, pushMessages, setOperation, setOperations, addBlobSize, setBlobSize };
|
|
20
24
|
async function createPrio({ correlationId, cataloger, oCatalogerIn, operation, operationSettings }) {
|
|
21
25
|
debugDev("createPrio");
|
|
22
|
-
const time =
|
|
26
|
+
const time = /* @__PURE__ */ new Date();
|
|
23
27
|
const newQueueItem = {
|
|
24
28
|
correlationId,
|
|
25
29
|
cataloger,
|
|
@@ -59,7 +63,7 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
async function createBulk({ correlationId, cataloger, oCatalogerIn, operation, contentType, recordLoadParams, stream, operationSettings }) {
|
|
62
|
-
const time =
|
|
66
|
+
const time = /* @__PURE__ */ new Date();
|
|
63
67
|
const newQueueItem = {
|
|
64
68
|
correlationId,
|
|
65
69
|
cataloger,
|
|
@@ -90,19 +94,42 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
90
94
|
try {
|
|
91
95
|
await new Promise((resolve, reject) => {
|
|
92
96
|
const outputStream = gridFSBucket.openUploadStream(correlationId);
|
|
93
|
-
|
|
97
|
+
outputStream.on("error", (error) => {
|
|
98
|
+
outputStream.destroy();
|
|
99
|
+
reject(error);
|
|
100
|
+
});
|
|
101
|
+
stream.on("error", (error) => {
|
|
102
|
+
outputStream.destroy();
|
|
103
|
+
reject(error);
|
|
104
|
+
}).on("data", (chunk) => outputStream.write(chunk)).on("end", () => outputStream.end(void 0, void 0, () => {
|
|
94
105
|
resolve(correlationId);
|
|
95
106
|
}));
|
|
96
107
|
});
|
|
97
108
|
logger.info(`New BULK queue item for ${operation} ${correlationId} has been made in ${collection}!`);
|
|
98
109
|
debug(`New BULK queue item for ${operation} ${correlationId} has been made in ${collection}!`);
|
|
99
|
-
|
|
110
|
+
const result = await operator.insertOne(newQueueItem);
|
|
111
|
+
if (!result.acknowledged) {
|
|
112
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR);
|
|
113
|
+
}
|
|
114
|
+
return { correlationId, acknowledged: result.acknowledged, queueItemState: newQueueItem.queueItemState };
|
|
100
115
|
} catch (error) {
|
|
101
116
|
const errorMessage = error.payload || error.message || "";
|
|
102
117
|
logError(error);
|
|
118
|
+
await removePartialContent(correlationId);
|
|
103
119
|
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
104
120
|
}
|
|
105
121
|
}
|
|
122
|
+
async function removePartialContent(correlationId2) {
|
|
123
|
+
try {
|
|
124
|
+
const files = await gridFSBucket.find({ filename: correlationId2 }).toArray();
|
|
125
|
+
for (const file of files) {
|
|
126
|
+
await gridFSBucket.delete(file._id);
|
|
127
|
+
logger.debug(`mongo/createBulk: removed partial GridFS file for ${correlationId2}`);
|
|
128
|
+
}
|
|
129
|
+
} catch (cleanupError) {
|
|
130
|
+
logger.debug(`mongo/createBulk: partial GridFS cleanup failed for ${correlationId2}: ${cleanupError.message}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
106
133
|
logger.debug(`No stream`);
|
|
107
134
|
debug(`Creating noStreamBulk`);
|
|
108
135
|
if (!stream) {
|
|
@@ -111,7 +138,7 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
111
138
|
if (result.acknowledged) {
|
|
112
139
|
logger.info(`New noStream BULK queue item for ${operation} ${correlationId} has been made in ${collection}`);
|
|
113
140
|
debug(`New noStream BULK queue item for ${operation} ${correlationId} has been made in ${collection}`);
|
|
114
|
-
return { correlationId, queueItemState: QUEUE_ITEM_STATE.VALIDATOR.WAITING_FOR_RECORDS };
|
|
141
|
+
return { correlationId, acknowledged: result.acknowledged, queueItemState: QUEUE_ITEM_STATE.VALIDATOR.WAITING_FOR_RECORDS };
|
|
115
142
|
}
|
|
116
143
|
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR);
|
|
117
144
|
} catch (error) {
|
|
@@ -122,19 +149,27 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
122
149
|
}
|
|
123
150
|
}
|
|
124
151
|
async function checkAndSetState({ correlationId, state, errorMessage = void 0, errorStatus = void 0 }) {
|
|
152
|
+
assertString(correlationId, "correlationId");
|
|
125
153
|
const timeOut = await checkTimeOut({ correlationId });
|
|
126
154
|
if (timeOut) {
|
|
127
|
-
|
|
155
|
+
const queueItem2 = await setState({ correlationId, state, errorMessage, errorStatus });
|
|
156
|
+
return { status: "updated", queueItem: queueItem2 };
|
|
128
157
|
}
|
|
129
|
-
|
|
158
|
+
const queueItem = await operator.findOne({ correlationId }, { projection: { _id: 0 } });
|
|
159
|
+
const status = queueItem && queueItem.queueItemState === QUEUE_ITEM_STATE.ABORT ? "timeout" : "unchanged";
|
|
160
|
+
return { status, queueItem };
|
|
130
161
|
}
|
|
131
162
|
async function checkAndSetImportJobState({ correlationId, operation, importJobState }) {
|
|
163
|
+
assertString(correlationId, "correlationId");
|
|
132
164
|
logger.debug(`${correlationId}, ${importJobState}, ${operation}`);
|
|
133
165
|
const timeOut = await checkTimeOut({ correlationId, operation, importJobState });
|
|
134
166
|
if (timeOut) {
|
|
135
|
-
|
|
167
|
+
const queueItem2 = await setImportJobState({ correlationId, operation, importJobState });
|
|
168
|
+
return { status: "updated", queueItem: queueItem2 };
|
|
136
169
|
}
|
|
137
|
-
|
|
170
|
+
const queueItem = await operator.findOne({ correlationId }, { projection: { _id: 0 } });
|
|
171
|
+
const status = queueItem && queueItem.queueItemState === QUEUE_ITEM_STATE.ABORT ? "timeout" : "unchanged";
|
|
172
|
+
return { status, queueItem };
|
|
138
173
|
}
|
|
139
174
|
async function query(params, showParams = {}) {
|
|
140
175
|
logger.debug(`Querying: ${JSON.stringify(params)}, ${JSON.stringify(showParams)}`);
|
|
@@ -184,6 +219,7 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
184
219
|
};
|
|
185
220
|
}
|
|
186
221
|
async function queryById({ correlationId, checkModTime = false }) {
|
|
222
|
+
assertString(correlationId, "correlationId");
|
|
187
223
|
if (checkModTime) {
|
|
188
224
|
debug(`queryById checkModTime: ${checkModTime}`);
|
|
189
225
|
await checkTimeOut({ correlationId });
|
|
@@ -193,14 +229,20 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
193
229
|
return result;
|
|
194
230
|
}
|
|
195
231
|
async function checkTimeOut({ correlationId }) {
|
|
196
|
-
|
|
232
|
+
assertString(correlationId, "correlationId");
|
|
233
|
+
const queueItem = await operator.findOne({ correlationId });
|
|
234
|
+
if (!queueItem) {
|
|
235
|
+
logger.silly(`${correlationId} not found in ${collection} - not a timeout`);
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
const { modificationTime, queueItemState: oldState, importJobState = { CREATE: IMPORT_JOB_STATE.EMPTY, UPDATE: IMPORT_JOB_STATE.EMPTY, FIX: IMPORT_JOB_STATE.EMPTY } } = queueItem;
|
|
197
239
|
if ([QUEUE_ITEM_STATE.ABORT, QUEUE_ITEM_STATE.ERROR, QUEUE_ITEM_STATE.DONE].includes(oldState)) {
|
|
198
240
|
logger.silly(`${correlationId} has already state: ${oldState}`);
|
|
199
241
|
return false;
|
|
200
242
|
}
|
|
201
|
-
const timeoutTime =
|
|
243
|
+
const timeoutTime = new Date(new Date(modificationTime).getTime() + timeoutMinutes * 6e4);
|
|
202
244
|
logger.silly(`${correlationId} timeOut @ ${timeoutTime}`);
|
|
203
|
-
if (timeoutTime
|
|
245
|
+
if (timeoutTime < /* @__PURE__ */ new Date()) {
|
|
204
246
|
const finalImportJobStates = [IMPORT_JOB_STATE.ABORT, IMPORT_JOB_STATE.DONE, IMPORT_JOB_STATE.EMPTY, IMPORT_JOB_STATE.ERROR];
|
|
205
247
|
if (!finalImportJobStates.includes(importJobState.CREATE)) {
|
|
206
248
|
await setImportJobState({ correlationId, operation: "CREATE", importJobState: IMPORT_JOB_STATE.ABORT });
|
|
@@ -221,25 +263,21 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
221
263
|
logger.info(`Removing from Mongo (${collection}) id: ${params.correlationId}`);
|
|
222
264
|
debug(`${JSON.stringify(params)}`);
|
|
223
265
|
debug(`Removing from Mongo (${collection}) id: ${params.correlationId}`);
|
|
224
|
-
|
|
225
|
-
logger.silly(`mongo/remove: clean: ${JSON.stringify(clean)}`);
|
|
226
|
-
debug(`mongo/remove: clean: ${JSON.stringify(clean)}`);
|
|
266
|
+
assertString(params.correlationId, "correlationId");
|
|
227
267
|
try {
|
|
228
|
-
const
|
|
229
|
-
debug(`
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
268
|
+
const removedContent = await removeContent({ correlationId: params.correlationId });
|
|
269
|
+
debug(`removedContent (removeContent result): ${JSON.stringify(removedContent)}`);
|
|
270
|
+
const deleteResult = await operator.deleteOne({ correlationId: params.correlationId });
|
|
271
|
+
debug(`deleteResult: ${JSON.stringify(deleteResult)}`);
|
|
272
|
+
return { removed: deleteResult.deletedCount > 0, deletedContent: removedContent };
|
|
235
273
|
} catch (err) {
|
|
236
274
|
if (err instanceof MongoDriverError) {
|
|
237
275
|
debug(err);
|
|
238
276
|
if (err.message.indexOf("File not found for id") !== -1) {
|
|
239
|
-
logger.silly(`mongo/remove: File not found, removing queueItem ${JSON.stringify(
|
|
240
|
-
debug(`mongo/remove: File not found, removing queueItem ${JSON.stringify(
|
|
241
|
-
await operator.deleteOne({ correlationId:
|
|
242
|
-
return
|
|
277
|
+
logger.silly(`mongo/remove: File not found, removing queueItem ${JSON.stringify(params.correlationId)} from ${collection}`);
|
|
278
|
+
debug(`mongo/remove: File not found, removing queueItem ${JSON.stringify(params.correlationId)} from ${collection}`);
|
|
279
|
+
const deleteResult = await operator.deleteOne({ correlationId: params.correlationId });
|
|
280
|
+
return { removed: deleteResult.deletedCount > 0, deletedContent: false };
|
|
243
281
|
}
|
|
244
282
|
logger.error(err.message);
|
|
245
283
|
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, err.message);
|
|
@@ -250,16 +288,24 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
250
288
|
async function readContent(correlationId) {
|
|
251
289
|
logger.info(`Reading content from mongo for id: ${correlationId} in ${collection}`);
|
|
252
290
|
debug(`Reading content from mongo for id: ${correlationId} in ${collection}`);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const result = await operator.findOne({ correlationId: clean });
|
|
291
|
+
assertString(correlationId, "correlationId");
|
|
292
|
+
const result = await operator.findOne({ correlationId });
|
|
256
293
|
debug(result);
|
|
257
294
|
if (result) {
|
|
258
295
|
const { operationSettings } = result;
|
|
259
|
-
|
|
296
|
+
let files = [];
|
|
297
|
+
if (operationSettings.prio === false) {
|
|
298
|
+
files = await gridFSBucket.find({ filename: correlationId }).toArray();
|
|
299
|
+
}
|
|
300
|
+
const hasContent = files.length > 0;
|
|
301
|
+
if (hasContent) {
|
|
260
302
|
return {
|
|
261
303
|
contentType: result.contentType,
|
|
262
|
-
|
|
304
|
+
// the file existence was verified by the find() above; a
|
|
305
|
+
// 'error' event on the returned stream (e.g. file deleted
|
|
306
|
+
// concurrently) is an unhandled event for the caller -> the
|
|
307
|
+
// contract is: the caller MUST attach an 'error' handler.
|
|
308
|
+
readStream: gridFSBucket.openDownloadStreamByName(correlationId)
|
|
263
309
|
};
|
|
264
310
|
}
|
|
265
311
|
logger.debug(`OperationSettings for ${correlationId}: ${JSON.stringify(operationSettings)}`);
|
|
@@ -272,8 +318,8 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
272
318
|
async function removeContent(params) {
|
|
273
319
|
logger.info(`Removing content from mongo for id: ${params.correlationId} in ${collection}`);
|
|
274
320
|
debug(`Removing content from mongo for id: ${params.correlationId} in ${collection}`);
|
|
275
|
-
|
|
276
|
-
const result = await gridFSBucket.find({ filename:
|
|
321
|
+
assertString(params.correlationId, "correlationId");
|
|
322
|
+
const result = await gridFSBucket.find({ filename: params.correlationId }).toArray();
|
|
277
323
|
debug(`mongo/removeContent: find bucket result ${JSON.stringify(result)}`);
|
|
278
324
|
if (result.length > 0) {
|
|
279
325
|
const [firstBucketResult] = result;
|
|
@@ -282,11 +328,17 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
282
328
|
return true;
|
|
283
329
|
}
|
|
284
330
|
logger.debug(`No files for ${params.correlationId} to delete`);
|
|
285
|
-
return
|
|
331
|
+
return false;
|
|
286
332
|
}
|
|
287
|
-
function getOne({ queueItemState, importJobState = void 0 }) {
|
|
333
|
+
async function getOne({ queueItemState, importJobState = void 0 }) {
|
|
288
334
|
logger.silly(`queueItemState: ${queueItemState}, importJobState: ${JSON.stringify(importJobState)}`);
|
|
289
|
-
|
|
335
|
+
if (queueItemState) {
|
|
336
|
+
assertString(queueItemState, "queueItemState");
|
|
337
|
+
}
|
|
338
|
+
if (importJobState) {
|
|
339
|
+
assertImportJobStateFilter(importJobState, "importJobState");
|
|
340
|
+
}
|
|
341
|
+
const cleanQueueItemState = queueItemState ? { queueItemState } : void 0;
|
|
290
342
|
const options = { projection: { _id: 0 } };
|
|
291
343
|
try {
|
|
292
344
|
if (queueItemState && importJobState === void 0) {
|
|
@@ -309,51 +361,77 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
309
361
|
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
310
362
|
}
|
|
311
363
|
}
|
|
312
|
-
function getStream(correlationId) {
|
|
364
|
+
async function getStream(correlationId) {
|
|
313
365
|
logger.info(`Forming stream from mongo for ${correlationId} in ${collection}`);
|
|
314
|
-
|
|
366
|
+
assertString(correlationId, "correlationId");
|
|
315
367
|
try {
|
|
316
|
-
|
|
368
|
+
const files = await gridFSBucket.find({ filename: correlationId }).toArray();
|
|
369
|
+
if (files.length === 0) {
|
|
370
|
+
logger.info(`getStream: file ${correlationId} not found in ${collection}`);
|
|
371
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `File ${correlationId} not found in ${collection}` });
|
|
372
|
+
}
|
|
373
|
+
return gridFSBucket.openDownloadStreamByName(correlationId);
|
|
317
374
|
} catch (error) {
|
|
375
|
+
if (error instanceof ApiError) {
|
|
376
|
+
throw error;
|
|
377
|
+
}
|
|
318
378
|
const errorMessage = error.payload || error.message || "";
|
|
319
379
|
logError(error);
|
|
320
380
|
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
321
381
|
}
|
|
322
382
|
}
|
|
323
383
|
async function pushIds({ correlationId, handledIds, rejectedIds }) {
|
|
384
|
+
if (!Array.isArray(handledIds) || !Array.isArray(rejectedIds)) {
|
|
385
|
+
throw new ApiError(httpStatus.BAD_REQUEST, "pushIds: handledIds and rejectedIds must be arrays");
|
|
386
|
+
}
|
|
387
|
+
assertString(correlationId, "correlationId");
|
|
324
388
|
logger.verbose(`Push ids (${handledIds.length}) and rejectedIds (${rejectedIds.length}) ${correlationId} to ${collection}`);
|
|
325
389
|
logger.debug(`ids (${handledIds.length}): ${JSON.stringify(handledIds)}, rejectedIds ${rejectedIds.length}: ${JSON.stringify(rejectedIds)}`);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
390
|
+
try {
|
|
391
|
+
await operator.updateOne({
|
|
392
|
+
correlationId
|
|
393
|
+
}, {
|
|
394
|
+
$set: {
|
|
395
|
+
modificationTime: /* @__PURE__ */ new Date()
|
|
396
|
+
},
|
|
397
|
+
$push: {
|
|
398
|
+
handledIds: { $each: handledIds },
|
|
399
|
+
rejectedIds: { $each: rejectedIds }
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
} catch (error) {
|
|
403
|
+
const errorMessage = error.payload || error.message || "";
|
|
404
|
+
logError(error);
|
|
405
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
406
|
+
}
|
|
338
407
|
}
|
|
339
408
|
async function pushMessages({ correlationId, messages, messageField = "messages" }) {
|
|
409
|
+
if (!Array.isArray(messages)) {
|
|
410
|
+
throw new ApiError(httpStatus.BAD_REQUEST, "pushMessages: messages must be an array");
|
|
411
|
+
}
|
|
412
|
+
assertString(correlationId, "correlationId");
|
|
413
|
+
assertString(messageField, "messageField");
|
|
340
414
|
logger.verbose(`Push messages (${messages.length}) to ${messageField} ${correlationId} to ${collection}`);
|
|
341
|
-
logger.silly(`Messages (${messages.length}): ${JSON.stringify(messages)}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
415
|
+
logger.silly(`Messages (${messages.length}): ${JSON.stringify(messages)}`);
|
|
416
|
+
try {
|
|
417
|
+
await operator.updateOne({
|
|
418
|
+
correlationId
|
|
419
|
+
}, {
|
|
420
|
+
$set: {
|
|
421
|
+
modificationTime: /* @__PURE__ */ new Date()
|
|
422
|
+
},
|
|
423
|
+
$push: {
|
|
424
|
+
[messageField]: { $each: messages }
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
} catch (error) {
|
|
428
|
+
const errorMessage = error.payload || error.message || "";
|
|
429
|
+
logError(error);
|
|
430
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
431
|
+
}
|
|
355
432
|
}
|
|
356
433
|
function setState({ correlationId, state, errorMessage = void 0, errorStatus = void 0 }) {
|
|
434
|
+
assertString(correlationId, "correlationId");
|
|
357
435
|
const errorString = errorMessage || errorStatus ? `, Error message: '${JSON.stringify(errorMessage) || ""}', Error status: '${errorStatus || ""}'` : "";
|
|
358
436
|
logger.info(`Setting queue-item state ${state} for ${correlationId}${errorString} to ${collection}`);
|
|
359
437
|
const stateInQueueItemStates = Object.values(QUEUE_ITEM_STATE).indexOf(state) > -1;
|
|
@@ -363,76 +441,89 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
363
441
|
debug(`Trying to set invalid state ${state}`);
|
|
364
442
|
throw new ApiError(httpStatus.BAD_REQUEST, "Trying to set invalid state");
|
|
365
443
|
}
|
|
366
|
-
const clean = sanitize(correlationId);
|
|
367
444
|
const updateValues = {
|
|
368
445
|
queueItemState: state,
|
|
369
|
-
modificationTime:
|
|
446
|
+
modificationTime: /* @__PURE__ */ new Date(),
|
|
370
447
|
errorMessage,
|
|
371
448
|
errorStatus
|
|
372
449
|
};
|
|
373
450
|
Object.keys(updateValues).forEach((key) => updateValues[key] === void 0 && delete updateValues[key]);
|
|
374
451
|
return operator.findOneAndUpdate(
|
|
375
|
-
{ correlationId
|
|
452
|
+
{ correlationId },
|
|
376
453
|
{ $set: updateValues },
|
|
377
454
|
{ projection: { _id: 0 }, returnDocument: "after" }
|
|
378
455
|
);
|
|
379
456
|
}
|
|
380
457
|
function setImportJobState({ correlationId, operation, importJobState }) {
|
|
458
|
+
assertString(correlationId, "correlationId");
|
|
381
459
|
logger.info(`Setting queue-item importJobState: {${operation}: ${importJobState}} for ${correlationId}`);
|
|
382
460
|
debug(`Setting queue-item importJobState: {${operation}: ${importJobState}} for ${correlationId}`);
|
|
383
|
-
const cleanCorrelationId = sanitize(correlationId);
|
|
384
|
-
const cleanImportJobState = sanitize(importJobState);
|
|
385
461
|
if (!(operation in OPERATIONS)) {
|
|
386
462
|
debug(`Error: ${operation} is not in ${JSON.stringify(OPERATIONS)}`);
|
|
387
463
|
throw new ApiError(httpStatus.BAD_REQUEST, "Invalid operation for import job state");
|
|
388
464
|
}
|
|
389
|
-
if (!(
|
|
390
|
-
debug(`Error: ${
|
|
465
|
+
if (!(importJobState in IMPORT_JOB_STATE)) {
|
|
466
|
+
debug(`Error: ${importJobState} is not in ${JSON.stringify(IMPORT_JOB_STATE)}`);
|
|
391
467
|
throw new ApiError(httpStatus.BAD_REQUEST, "Invalid import job state");
|
|
392
468
|
}
|
|
393
|
-
const newJobState = getNewJobState(operation,
|
|
394
|
-
function getNewJobState(operation2,
|
|
469
|
+
const newJobState = getNewJobState(operation, importJobState);
|
|
470
|
+
function getNewJobState(operation2, importJobState2) {
|
|
395
471
|
if (operation2 === OPERATIONS.CREATE) {
|
|
396
|
-
return { "importJobState.CREATE":
|
|
472
|
+
return { "importJobState.CREATE": importJobState2 };
|
|
397
473
|
}
|
|
398
474
|
if (operation2 === OPERATIONS.UPDATE) {
|
|
399
|
-
return { "importJobState.UPDATE":
|
|
475
|
+
return { "importJobState.UPDATE": importJobState2 };
|
|
400
476
|
}
|
|
401
477
|
if (operation2 === OPERATIONS.FIX) {
|
|
402
|
-
return { "importJobState.FIX":
|
|
478
|
+
return { "importJobState.FIX": importJobState2 };
|
|
403
479
|
}
|
|
404
480
|
throw new ApiError("400", "Invalid operation for import job state");
|
|
405
481
|
}
|
|
406
482
|
return operator.findOneAndUpdate({
|
|
407
|
-
correlationId
|
|
483
|
+
correlationId
|
|
408
484
|
}, {
|
|
409
485
|
$set: {
|
|
410
486
|
...newJobState,
|
|
411
|
-
modificationTime:
|
|
487
|
+
modificationTime: /* @__PURE__ */ new Date()
|
|
412
488
|
}
|
|
413
489
|
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
414
490
|
}
|
|
491
|
+
function unwrapAndUpdateResult(result, correlationId) {
|
|
492
|
+
if (result === null || result === void 0) {
|
|
493
|
+
logger.info(`Queue item ${correlationId} not found in ${collection}`);
|
|
494
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `Job ${correlationId} not found.` });
|
|
495
|
+
}
|
|
496
|
+
return result;
|
|
497
|
+
}
|
|
415
498
|
async function setOperation({ correlationId, operation }) {
|
|
499
|
+
assertString(correlationId, "correlationId");
|
|
416
500
|
const newOperation = operation;
|
|
417
|
-
const
|
|
501
|
+
const existing = await operator.findOne({ correlationId });
|
|
502
|
+
if (!existing) {
|
|
503
|
+
logger.info(`Setting queue-item operation: queue item ${correlationId} not found in ${collection}`);
|
|
504
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `Job ${correlationId} not found.` });
|
|
505
|
+
}
|
|
506
|
+
const { operation: oldOperation } = existing;
|
|
418
507
|
logger.info(`Setting queue-item operation from ${oldOperation} to ${newOperation} for ${correlationId} to ${collection}`);
|
|
419
|
-
const cleanCorrelationId = sanitize(correlationId);
|
|
420
|
-
const cleanNewOperation = sanitize(newOperation);
|
|
421
508
|
const result = await operator.findOneAndUpdate({
|
|
422
|
-
correlationId
|
|
509
|
+
correlationId
|
|
423
510
|
}, {
|
|
424
511
|
$set: {
|
|
425
|
-
operation:
|
|
426
|
-
modificationTime:
|
|
512
|
+
operation: newOperation,
|
|
513
|
+
modificationTime: /* @__PURE__ */ new Date()
|
|
427
514
|
}
|
|
428
515
|
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
429
516
|
debugDev(`${JSON.stringify(result)}`);
|
|
430
|
-
return result
|
|
517
|
+
return unwrapAndUpdateResult(result, correlationId);
|
|
431
518
|
}
|
|
432
519
|
async function setOperations({ correlationId, addOperation, removeOperation = void 0 }) {
|
|
433
|
-
|
|
434
|
-
const queueItem = await operator.findOne({ correlationId
|
|
520
|
+
assertString(correlationId, "correlationId");
|
|
521
|
+
const queueItem = await operator.findOne({ correlationId });
|
|
435
522
|
logger.silly(`We found a queueItem: ${JSON.stringify(queueItem)}`);
|
|
523
|
+
if (!queueItem) {
|
|
524
|
+
logger.info(`Setting queue-item operations: queue item ${correlationId} not found in ${collection}`);
|
|
525
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `Job ${correlationId} not found.` });
|
|
526
|
+
}
|
|
436
527
|
const oldOperations = queueItem.operations;
|
|
437
528
|
logger.info(`Setting queue-item operations from ${JSON.stringify(oldOperations)} by adding ${addOperation} and removing ${removeOperation} for ${correlationId} to ${collection}`);
|
|
438
529
|
const operationsAfterRemove = oldOperations.filter((operation) => operation !== removeOperation);
|
|
@@ -440,27 +531,27 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
440
531
|
logger.silly(`operationsAfterRemove: ${operationsAfterRemove}`);
|
|
441
532
|
logger.silly(`operationAfterRemoveAndAdd: ${operationsAfterRemoveAndAdd}`);
|
|
442
533
|
const result = await operator.findOneAndUpdate({
|
|
443
|
-
correlationId
|
|
534
|
+
correlationId
|
|
444
535
|
}, {
|
|
445
536
|
$set: {
|
|
446
537
|
operations: operationsAfterRemoveAndAdd,
|
|
447
|
-
modificationTime:
|
|
538
|
+
modificationTime: /* @__PURE__ */ new Date()
|
|
448
539
|
}
|
|
449
540
|
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
450
541
|
debugDev(`${JSON.stringify(result)}`);
|
|
451
|
-
return result
|
|
542
|
+
return unwrapAndUpdateResult(result, correlationId);
|
|
452
543
|
}
|
|
453
544
|
async function addBlobSize({ correlationId }) {
|
|
454
|
-
|
|
545
|
+
assertString(correlationId, "correlationId");
|
|
455
546
|
const result = await operator.findOneAndUpdate({
|
|
456
|
-
correlationId
|
|
547
|
+
correlationId,
|
|
457
548
|
queueItemState: QUEUE_ITEM_STATE.VALIDATOR.WAITING_FOR_RECORDS
|
|
458
549
|
}, {
|
|
459
550
|
$inc: {
|
|
460
551
|
blobSize: 1
|
|
461
552
|
},
|
|
462
553
|
$set: {
|
|
463
|
-
modificationTime:
|
|
554
|
+
modificationTime: /* @__PURE__ */ new Date()
|
|
464
555
|
}
|
|
465
556
|
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
466
557
|
logger.verbose(`AddBlobSizeResult in mongo: ${JSON.stringify(result)}`);
|
|
@@ -468,14 +559,14 @@ export default async function(MONGO_URI, collection, db = "rest-api") {
|
|
|
468
559
|
return result;
|
|
469
560
|
}
|
|
470
561
|
async function setBlobSize({ correlationId, blobSize }) {
|
|
471
|
-
|
|
472
|
-
|
|
562
|
+
assertString(correlationId, "correlationId");
|
|
563
|
+
assertNumber(blobSize, "blobSize");
|
|
473
564
|
const result = await operator.findOneAndUpdate({
|
|
474
|
-
correlationId
|
|
565
|
+
correlationId
|
|
475
566
|
}, {
|
|
476
567
|
$set: {
|
|
477
|
-
blobSize
|
|
478
|
-
modificationTime:
|
|
568
|
+
blobSize,
|
|
569
|
+
modificationTime: /* @__PURE__ */ new Date()
|
|
479
570
|
}
|
|
480
571
|
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
481
572
|
logger.verbose(`SetBlobSizeResult in mongo: ${JSON.stringify(result)}`);
|