@natlibfi/melinda-rest-api-commons 6.0.1 → 6.2.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/.github/workflows/melinda-node-tests-and-publish.yml +4 -2
- package/README.md +82 -0
- package/dist/amqp.d.ts +41 -0
- package/dist/amqp.d.ts.map +1 -0
- package/dist/amqp.js +242 -218
- package/dist/amqp.js.map +1 -7
- package/dist/constants.d.ts +49 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +38 -38
- package/dist/constants.js.map +1 -7
- package/dist/helpers/conversion.d.ts +8 -0
- package/dist/helpers/conversion.d.ts.map +1 -0
- package/dist/helpers/conversion.js +70 -65
- package/dist/helpers/conversion.js.map +1 -7
- package/dist/helpers/fix-constants.d.ts +76 -0
- package/dist/helpers/fix-constants.d.ts.map +1 -0
- package/dist/helpers/fix-constants.js +41 -41
- package/dist/helpers/fix-constants.js.map +1 -7
- package/dist/helpers/fix-handle-tempurns.d.ts +3 -0
- package/dist/helpers/fix-handle-tempurns.d.ts.map +1 -0
- package/dist/helpers/fix-handle-tempurns.js +73 -71
- package/dist/helpers/fix-handle-tempurns.js.map +1 -7
- package/dist/helpers/fix-strip-f884s.d.ts +10 -0
- package/dist/helpers/fix-strip-f884s.d.ts.map +1 -0
- package/dist/helpers/fix-strip-f884s.js +163 -151
- package/dist/helpers/fix-strip-f884s.js.map +1 -7
- package/dist/helpers/fix.d.ts +6 -0
- package/dist/helpers/fix.d.ts.map +1 -0
- package/dist/helpers/fix.js +133 -117
- package/dist/helpers/fix.js.map +1 -7
- package/dist/helpers/validation.d.ts +9 -0
- package/dist/helpers/validation.d.ts.map +1 -0
- package/dist/helpers/validation.js +14 -16
- package/dist/helpers/validation.js.map +1 -7
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -7
- package/dist/mongo.d.ts +165 -0
- package/dist/mongo.d.ts.map +1 -0
- package/dist/mongo.js +603 -464
- package/dist/mongo.js.map +1 -7
- package/dist/mongoError.d.ts +2 -0
- package/dist/mongoError.d.ts.map +1 -0
- package/dist/mongoError.js +19 -0
- package/dist/mongoError.js.map +1 -0
- package/dist/mongoLog.d.ts +50 -0
- package/dist/mongoLog.d.ts.map +1 -0
- package/dist/mongoLog.js +282 -172
- package/dist/mongoLog.js.map +1 -7
- package/dist/utils.d.ts +36 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +118 -87
- package/dist/utils.js.map +1 -7
- package/eslint.config.ts +66 -0
- package/package.json +23 -25
- package/test/amqp-error-branches.test.ts +551 -0
- package/{tests/amqp.healthtest.js → test/amqp.healthtest.ts} +19 -7
- package/{tests/amqp.tests.localtest.js → test/amqp.tests.localtest.ts} +66 -52
- package/{tests/helpers/conversion.test.js → test/helpers/conversion.test.ts} +39 -11
- package/test/helpers/fix-edge.test.ts +201 -0
- package/test/helpers/fix.test.ts +65 -0
- package/{tests/helpers/validation.test.js → test/helpers/validation.test.ts} +13 -8
- package/{tests/mongo-add-blob-size.test.js → test/mongo-add-blob-size.test.ts} +14 -15
- package/{tests/mongo-check-and-check-state.test.js → test/mongo-check-and-check-state.test.ts} +9 -9
- package/{tests/mongo-check-and-set-import-job-state.test.js → test/mongo-check-and-set-import-job-state.test.ts} +9 -10
- package/{tests/mongo-check-timeout.test.js → test/mongo-check-timeout.test.ts} +6 -9
- package/{tests/mongo-create-bulk.test.js → test/mongo-create-bulk.test.ts} +6 -7
- package/{tests/mongo-create-prio.test.js → test/mongo-create-prio.test.ts} +6 -6
- package/test/mongo-error-branches.test.ts +883 -0
- package/{tests/mongo-get-one.test.js → test/mongo-get-one.test.ts} +6 -6
- package/{tests/mongo-get-stream.test.js → test/mongo-get-stream.test.ts} +10 -9
- package/{tests/mongo-push-ids.test.js → test/mongo-push-ids.test.ts} +6 -6
- package/{tests/mongo-push-messages.test.js → test/mongo-push-messages.test.ts} +6 -6
- package/{tests/mongo-query-by-id.test.js → test/mongo-query-by-id.test.ts} +6 -9
- package/{tests/mongo-query.test.js → test/mongo-query.test.ts} +6 -7
- package/{tests/mongo-read-content.test.js → test/mongo-read-content.test.ts} +16 -9
- package/{tests/mongo-remove.test.js → test/mongo-remove.test.ts} +6 -8
- package/{tests/mongo-set-blob-size.test.js → test/mongo-set-blob-size.test.ts} +6 -6
- package/{tests/mongo-set-import-job-state.test.js → test/mongo-set-import-job-state.test.ts} +6 -6
- package/{tests/mongo-set-operation.test.js → test/mongo-set-operation.test.ts} +6 -6
- package/{tests/mongo-set-operations.test.js → test/mongo-set-operations.test.ts} +6 -6
- package/{tests/mongo-set-state.test.js → test/mongo-set-state.test.ts} +6 -6
- package/test/mongoLog-protect.test.ts +182 -0
- package/test/mongoLog.test.ts +191 -0
- package/{tests/testUtils.js → test/testUtils.ts} +49 -15
- package/test/utils.test.ts +360 -0
- package/tsconfig.json +62 -0
- package/tsconfig.test.json +17 -0
- package/dist/helpers/fix-utils.js +0 -39
- package/dist/helpers/fix-utils.js.map +0 -7
- package/eslint.config.js +0 -53
- package/tests/helpers/fix.test.js +0 -41
- package/tests/mongoLog.test.js +0 -84
package/dist/mongo.js
CHANGED
|
@@ -1,486 +1,625 @@
|
|
|
1
|
-
import { MongoClient, GridFSBucket, MongoDriverError } from
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import createDebugLogger from "debug";
|
|
6
|
-
import { createLogger } from "@natlibfi/melinda-backend-commons";
|
|
7
|
-
import { Error as ApiError, parseBoolean } from "@natlibfi/melinda-commons";
|
|
1
|
+
import { MongoClient, GridFSBucket, MongoDriverError } from 'mongodb';
|
|
2
|
+
import httpStatus from 'http-status';
|
|
3
|
+
import createDebugLogger from 'debug';
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
cataloger,
|
|
26
|
-
operation,
|
|
27
|
-
operations: [operation],
|
|
28
|
-
oCatalogerIn,
|
|
29
|
-
operationSettings: {
|
|
30
|
-
prio: true,
|
|
31
|
-
...operationSettings
|
|
32
|
-
},
|
|
33
|
-
queueItemState: QUEUE_ITEM_STATE.VALIDATOR.PENDING_VALIDATION,
|
|
34
|
-
blobSize: 1,
|
|
35
|
-
importJobState: {
|
|
36
|
-
CREATE: IMPORT_JOB_STATE.EMPTY,
|
|
37
|
-
UPDATE: IMPORT_JOB_STATE.EMPTY,
|
|
38
|
-
FIX: IMPORT_JOB_STATE.EMPTY
|
|
39
|
-
},
|
|
40
|
-
records: [],
|
|
41
|
-
errorMessage: "",
|
|
42
|
-
errorStatus: "",
|
|
43
|
-
creationTime: time,
|
|
44
|
-
modificationTime: time
|
|
45
|
-
};
|
|
46
|
-
try {
|
|
47
|
-
debugDev(`Inserting: ${JSON.stringify(newQueueItem)} to ${collection}}`);
|
|
48
|
-
const result = await operator.insertOne(newQueueItem);
|
|
49
|
-
debugDev(JSON.stringify(result));
|
|
50
|
-
if (result.acknowledged) {
|
|
51
|
-
logger.info(`New PRIO queue item for ${operation} ${correlationId} has been made in ${collection}`);
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
const errorMessage = error.payload || error.message || "";
|
|
57
|
-
logError(error);
|
|
58
|
-
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
6
|
+
import { logError, assertString, assertNumber, assertImportJobStateFilter } from "./utils.js";
|
|
7
|
+
import { withMongoError } from "./mongoError.js";
|
|
8
|
+
export default async function (MONGO_URI, collection, db = 'rest-api', deps = {}) {
|
|
9
|
+
const logger = createLogger();
|
|
10
|
+
const timeoutMinutes = Number.parseInt(process.env['MONGO_TIMEOUT_MINUTES'], 10) || 1;
|
|
11
|
+
logger.debug(`checkTimeOut window: ${timeoutMinutes} minute(s) (override with MONGO_TIMEOUT_MINUTES)`);
|
|
12
|
+
const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons/mongo');
|
|
13
|
+
const debugDev = debug.extend(':dev');
|
|
14
|
+
const stubbed = Boolean(deps.operator) && Boolean(deps.gridFSBucket);
|
|
15
|
+
let gridFSBucket = deps.gridFSBucket;
|
|
16
|
+
let operator = deps.operator;
|
|
17
|
+
if (!stubbed) {
|
|
18
|
+
const client = await MongoClient.connect(MONGO_URI);
|
|
19
|
+
const realDb = client.db(db);
|
|
20
|
+
gridFSBucket = gridFSBucket ?? new GridFSBucket(realDb, { bucketName: collection });
|
|
21
|
+
operator = operator ?? realDb.collection(collection);
|
|
59
22
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
errorMessage: "",
|
|
84
|
-
errorStatus: "",
|
|
85
|
-
creationTime: time,
|
|
86
|
-
modificationTime: time
|
|
23
|
+
debugDev(`mongo: ${MONGO_URI}, db: ${db}, collection: ${collection}`);
|
|
24
|
+
return {
|
|
25
|
+
createPrio,
|
|
26
|
+
createBulk,
|
|
27
|
+
checkAndSetState: (params) => withMongoError(() => checkAndSetState(params)),
|
|
28
|
+
checkAndSetImportJobState: (params) => withMongoError(() => checkAndSetImportJobState(params)),
|
|
29
|
+
query: (params, showParams) => withMongoError(() => query(params, showParams)),
|
|
30
|
+
createProjection,
|
|
31
|
+
queryById: (params) => withMongoError(() => queryById(params)),
|
|
32
|
+
checkTimeOut: (params) => withMongoError(() => checkTimeOut(params)),
|
|
33
|
+
remove,
|
|
34
|
+
readContent: (correlationId) => withMongoError(() => readContent(correlationId)),
|
|
35
|
+
removeContent: (params) => withMongoError(() => removeContent(params)),
|
|
36
|
+
getOne,
|
|
37
|
+
getStream,
|
|
38
|
+
setState: (params) => withMongoError(() => setState(params)),
|
|
39
|
+
setImportJobState: (params) => withMongoError(() => setImportJobState(params)),
|
|
40
|
+
pushIds,
|
|
41
|
+
pushMessages,
|
|
42
|
+
setOperation: (params) => withMongoError(() => setOperation(params)),
|
|
43
|
+
setOperations: (params) => withMongoError(() => setOperations(params)),
|
|
44
|
+
addBlobSize: (params) => withMongoError(() => addBlobSize(params)),
|
|
45
|
+
setBlobSize: (params) => withMongoError(() => setBlobSize(params))
|
|
87
46
|
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
47
|
+
async function createPrio({ correlationId, cataloger, oCatalogerIn, operation, operationSettings }) {
|
|
48
|
+
debugDev('createPrio');
|
|
49
|
+
const time = new Date();
|
|
50
|
+
const newQueueItem = {
|
|
51
|
+
correlationId,
|
|
52
|
+
cataloger,
|
|
53
|
+
operation,
|
|
54
|
+
operations: [operation],
|
|
55
|
+
oCatalogerIn,
|
|
56
|
+
operationSettings: {
|
|
57
|
+
prio: true,
|
|
58
|
+
...operationSettings
|
|
59
|
+
},
|
|
60
|
+
queueItemState: QUEUE_ITEM_STATE.VALIDATOR.PENDING_VALIDATION,
|
|
61
|
+
blobSize: 1,
|
|
62
|
+
importJobState: {
|
|
63
|
+
CREATE: IMPORT_JOB_STATE.EMPTY,
|
|
64
|
+
UPDATE: IMPORT_JOB_STATE.EMPTY,
|
|
65
|
+
FIX: IMPORT_JOB_STATE.EMPTY
|
|
66
|
+
},
|
|
67
|
+
records: [],
|
|
68
|
+
errorMessage: '',
|
|
69
|
+
errorStatus: '',
|
|
70
|
+
creationTime: time,
|
|
71
|
+
modificationTime: time
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
debugDev(`Inserting: ${JSON.stringify(newQueueItem)} to ${collection}}`);
|
|
75
|
+
const result = await operator.insertOne(newQueueItem);
|
|
76
|
+
debugDev(JSON.stringify(result));
|
|
77
|
+
if (result.acknowledged) {
|
|
78
|
+
logger.info(`New PRIO queue item for ${operation} ${correlationId} has been made in ${collection}`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, undefined);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const apiError = error;
|
|
85
|
+
const errorMessage = apiError.payload || apiError.message || '';
|
|
86
|
+
logError(error);
|
|
87
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
88
|
+
}
|
|
122
89
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
90
|
+
async function createBulk({ correlationId, cataloger, oCatalogerIn, operation, contentType, recordLoadParams, stream, operationSettings }) {
|
|
91
|
+
const time = new Date();
|
|
92
|
+
const newQueueItem = {
|
|
93
|
+
correlationId,
|
|
94
|
+
cataloger,
|
|
95
|
+
oCatalogerIn,
|
|
96
|
+
operation,
|
|
97
|
+
operations: [operation],
|
|
98
|
+
operationSettings: {
|
|
99
|
+
prio: false,
|
|
100
|
+
...operationSettings
|
|
101
|
+
},
|
|
102
|
+
contentType,
|
|
103
|
+
recordLoadParams,
|
|
104
|
+
queueItemState: stream ? QUEUE_ITEM_STATE.VALIDATOR.UPLOADING : QUEUE_ITEM_STATE.VALIDATOR.WAITING_FOR_RECORDS,
|
|
105
|
+
blobSize: 0,
|
|
106
|
+
importJobState: {
|
|
107
|
+
CREATE: IMPORT_JOB_STATE.EMPTY,
|
|
108
|
+
UPDATE: IMPORT_JOB_STATE.EMPTY,
|
|
109
|
+
FIX: IMPORT_JOB_STATE.EMPTY
|
|
110
|
+
},
|
|
111
|
+
records: [],
|
|
112
|
+
errorMessage: '',
|
|
113
|
+
errorStatus: '',
|
|
114
|
+
creationTime: time,
|
|
115
|
+
modificationTime: time
|
|
116
|
+
};
|
|
117
|
+
if (stream) {
|
|
118
|
+
debug(`Creating streamBulk`);
|
|
119
|
+
try {
|
|
120
|
+
await new Promise((resolve, reject) => {
|
|
121
|
+
const outputStream = gridFSBucket.openUploadStream(correlationId);
|
|
122
|
+
outputStream.on('error', (error) => {
|
|
123
|
+
outputStream.destroy();
|
|
124
|
+
reject(error);
|
|
125
|
+
});
|
|
126
|
+
stream
|
|
127
|
+
.on('error', (error) => {
|
|
128
|
+
outputStream.destroy();
|
|
129
|
+
reject(error);
|
|
130
|
+
})
|
|
131
|
+
.on('data', chunk => outputStream.write(chunk))
|
|
132
|
+
.on('end', () => outputStream.end(undefined, () => {
|
|
133
|
+
resolve(correlationId);
|
|
134
|
+
}));
|
|
135
|
+
});
|
|
136
|
+
logger.info(`New BULK queue item for ${operation} ${correlationId} has been made in ${collection}!`);
|
|
137
|
+
debug(`New BULK queue item for ${operation} ${correlationId} has been made in ${collection}!`);
|
|
138
|
+
const result = await operator.insertOne(newQueueItem);
|
|
139
|
+
if (!result.acknowledged) {
|
|
140
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, undefined);
|
|
141
|
+
}
|
|
142
|
+
return { correlationId, acknowledged: result.acknowledged, queueItemState: newQueueItem.queueItemState };
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
const apiError = error;
|
|
146
|
+
const errorMessage = apiError.payload || apiError.message || '';
|
|
147
|
+
logError(error);
|
|
148
|
+
await removePartialContent(correlationId);
|
|
149
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function removePartialContent(correlationId) {
|
|
153
|
+
try {
|
|
154
|
+
const files = await gridFSBucket.find({ filename: correlationId }).toArray();
|
|
155
|
+
for (const file of files) {
|
|
156
|
+
await gridFSBucket.delete(file._id);
|
|
157
|
+
logger.debug(`mongo/createBulk: removed partial GridFS file for ${correlationId}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (cleanupError) {
|
|
161
|
+
const apiError = cleanupError;
|
|
162
|
+
logger.debug(`mongo/createBulk: partial GridFS cleanup failed for ${correlationId}: ${apiError.message}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
logger.debug(`No stream`);
|
|
166
|
+
debug(`Creating noStreamBulk`);
|
|
167
|
+
if (!stream) {
|
|
168
|
+
try {
|
|
169
|
+
const result = await operator.insertOne(newQueueItem);
|
|
170
|
+
if (result.acknowledged) {
|
|
171
|
+
logger.info(`New noStream BULK queue item for ${operation} ${correlationId} has been made in ${collection}`);
|
|
172
|
+
debug(`New noStream BULK queue item for ${operation} ${correlationId} has been made in ${collection}`);
|
|
173
|
+
return { correlationId, acknowledged: result.acknowledged, queueItemState: QUEUE_ITEM_STATE.VALIDATOR.WAITING_FOR_RECORDS };
|
|
174
|
+
}
|
|
175
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, undefined);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
const apiError = error;
|
|
179
|
+
const errorMessage = apiError.payload || apiError.message || '';
|
|
180
|
+
logError(error);
|
|
181
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return undefined;
|
|
128
185
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
186
|
+
async function checkAndSetState({ correlationId, state, errorMessage = undefined, errorStatus = undefined }) {
|
|
187
|
+
assertString(correlationId, 'correlationId');
|
|
188
|
+
const timeOut = await checkTimeOut({ correlationId });
|
|
189
|
+
if (timeOut) {
|
|
190
|
+
const queueItem = await setState({ correlationId, state, errorMessage, errorStatus });
|
|
191
|
+
return { status: 'updated', queueItem };
|
|
192
|
+
}
|
|
193
|
+
const queueItem = await operator.findOne({ correlationId }, { projection: { _id: 0 } });
|
|
194
|
+
const status = queueItem && queueItem.queueItemState === QUEUE_ITEM_STATE.ABORT ? 'timeout' : 'unchanged';
|
|
195
|
+
return { status, queueItem };
|
|
136
196
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
function createProjection(showParams = {}) {
|
|
150
|
-
logger.silly(`Creating projection for query: ${JSON.stringify(showParams)}`);
|
|
151
|
-
debug(`Creating projection for query: ${JSON.stringify(showParams)}`);
|
|
152
|
-
const { showAll = 0, showOperations = 0, showOperationSettings = 0, showRecordLoadParams = 0, showImportJobState = 0 } = showParams;
|
|
153
|
-
const combinedShowParams = {
|
|
154
|
-
showAll,
|
|
155
|
-
showOperations,
|
|
156
|
-
showOperationSettings,
|
|
157
|
-
showRecordLoadParams,
|
|
158
|
-
showImportJobState
|
|
159
|
-
};
|
|
160
|
-
logger.debug(`showAll: ${showAll}, showOperations: ${showOperations}, showOperationSettings: ${showOperationSettings}, showRecordLoadParams: ${showRecordLoadParams}, showImportJobState: ${showImportJobState}`);
|
|
161
|
-
debug(`showAll: ${showAll}, showOperations: ${showOperations}, showOperationSettings: ${showOperationSettings}, showRecordLoadParams: ${showRecordLoadParams}, showImportJobState: ${showImportJobState}`);
|
|
162
|
-
debug(`${JSON.stringify(combinedShowParams)}`);
|
|
163
|
-
if (parseBoolean(showAll)) {
|
|
164
|
-
debug(`ShowAll: ${showAll}`);
|
|
165
|
-
return {
|
|
166
|
-
_id: 0
|
|
167
|
-
};
|
|
197
|
+
async function checkAndSetImportJobState({ correlationId, operation, importJobState }) {
|
|
198
|
+
assertString(correlationId, 'correlationId');
|
|
199
|
+
logger.debug(`${correlationId}, ${importJobState}, ${operation}`);
|
|
200
|
+
const timeOut = await checkTimeOut({ correlationId, operation, importJobState });
|
|
201
|
+
if (timeOut) {
|
|
202
|
+
const queueItem = await setImportJobState({ correlationId, operation, importJobState });
|
|
203
|
+
return { status: 'updated', queueItem };
|
|
204
|
+
}
|
|
205
|
+
const queueItem = await operator.findOne({ correlationId }, { projection: { _id: 0 } });
|
|
206
|
+
const status = queueItem && queueItem.queueItemState === QUEUE_ITEM_STATE.ABORT ? 'timeout' : 'unchanged';
|
|
207
|
+
return { status, queueItem };
|
|
168
208
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
_id: 0,
|
|
183
|
-
...excludeObject
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
async function queryById({ correlationId, checkModTime = false }) {
|
|
187
|
-
if (checkModTime) {
|
|
188
|
-
debug(`queryById checkModTime: ${checkModTime}`);
|
|
189
|
-
await checkTimeOut({ correlationId });
|
|
190
|
-
return queryById({ correlationId });
|
|
209
|
+
async function query(params, showParams = {}) {
|
|
210
|
+
logger.debug(`Querying: ${JSON.stringify(params)}, ${JSON.stringify(showParams)}`);
|
|
211
|
+
debug(`Querying: ${JSON.stringify(params)}, ${JSON.stringify(showParams)}`);
|
|
212
|
+
const { limit = 1000, skip = 0, ...rest } = params;
|
|
213
|
+
const result = await operator.find(rest, { projection: createProjection(showParams) })
|
|
214
|
+
.limit(parseInt(String(limit), 10))
|
|
215
|
+
.skip(parseInt(String(skip), 10))
|
|
216
|
+
.toArray();
|
|
217
|
+
logger.debug(`Query result: ${result.length > 0 ? 'Found!' : 'Not found!'}`);
|
|
218
|
+
logger.silly(`${JSON.stringify(result)}`);
|
|
219
|
+
debug(`${JSON.stringify(result)}`);
|
|
220
|
+
return result;
|
|
191
221
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
222
|
+
function createProjection(showParams = {}) {
|
|
223
|
+
logger.silly(`Creating projection for query: ${JSON.stringify(showParams)}`);
|
|
224
|
+
debug(`Creating projection for query: ${JSON.stringify(showParams)}`);
|
|
225
|
+
const { showAll = 0, showOperations = 0, showOperationSettings = 0, showRecordLoadParams = 0, showImportJobState = 0 } = showParams;
|
|
226
|
+
const combinedShowParams = {
|
|
227
|
+
showAll,
|
|
228
|
+
showOperations,
|
|
229
|
+
showOperationSettings,
|
|
230
|
+
showRecordLoadParams,
|
|
231
|
+
showImportJobState
|
|
232
|
+
};
|
|
233
|
+
logger.debug(`showAll: ${showAll}, showOperations: ${showOperations}, showOperationSettings: ${showOperationSettings}, showRecordLoadParams: ${showRecordLoadParams}, showImportJobState: ${showImportJobState}`);
|
|
234
|
+
debug(`showAll: ${showAll}, showOperations: ${showOperations}, showOperationSettings: ${showOperationSettings}, showRecordLoadParams: ${showRecordLoadParams}, showImportJobState: ${showImportJobState}`);
|
|
235
|
+
debug(`${JSON.stringify(combinedShowParams)}`);
|
|
236
|
+
if (parseBoolean(showAll)) {
|
|
237
|
+
debug(`ShowAll: ${showAll}`);
|
|
238
|
+
return {
|
|
239
|
+
_id: 0
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const showParamToField = {
|
|
243
|
+
'showOperations': 'operations',
|
|
244
|
+
'showOperationSettings': 'operationSettings',
|
|
245
|
+
'showRecordLoadParams': 'recordLoadParams',
|
|
246
|
+
'showImportJobState': 'importJobState'
|
|
247
|
+
};
|
|
248
|
+
const result = Object.keys(combinedShowParams)
|
|
249
|
+
.filter(param => param !== 'showAll' && !parseBoolean(combinedShowParams[param]))
|
|
250
|
+
.filter((param) => param in showParamToField)
|
|
251
|
+
.map(param => showParamToField[param]);
|
|
252
|
+
logger.silly(`We want to exclude from projection: ${JSON.stringify(result)}`);
|
|
253
|
+
debug(`We want to exclude from projection: ${JSON.stringify(result)}`);
|
|
254
|
+
const excludeObject = Object.fromEntries(result.map(param => [param, 0]));
|
|
255
|
+
logger.silly(`We want to exclude from projection: ${JSON.stringify(excludeObject)}`);
|
|
256
|
+
debug(`We want to exclude from projection: ${JSON.stringify(excludeObject)}`);
|
|
257
|
+
return {
|
|
258
|
+
_id: 0,
|
|
259
|
+
...excludeObject
|
|
260
|
+
};
|
|
200
261
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
if (!finalImportJobStates.includes(importJobState.FIX)) {
|
|
212
|
-
await setImportJobState({ correlationId, operation: "FIX", importJobState: IMPORT_JOB_STATE.ABORT });
|
|
213
|
-
}
|
|
214
|
-
await setState({ correlationId, state: QUEUE_ITEM_STATE.ABORT, errorStatus: httpStatus.REQUEST_TIMEOUT, errorMessage: `Timeout in ${oldState}` });
|
|
215
|
-
return false;
|
|
262
|
+
async function queryById({ correlationId, checkModTime = false }) {
|
|
263
|
+
assertString(correlationId, 'correlationId');
|
|
264
|
+
if (checkModTime) {
|
|
265
|
+
debug(`queryById checkModTime: ${checkModTime}`);
|
|
266
|
+
await checkTimeOut({ correlationId });
|
|
267
|
+
return queryById({ correlationId });
|
|
268
|
+
}
|
|
269
|
+
const result = await operator.findOne({ correlationId }, { projection: { _id: 0 } });
|
|
270
|
+
return result;
|
|
216
271
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
272
|
+
async function checkTimeOut({ correlationId }) {
|
|
273
|
+
assertString(correlationId, 'correlationId');
|
|
274
|
+
const queueItem = await operator.findOne({ correlationId });
|
|
275
|
+
if (!queueItem) {
|
|
276
|
+
logger.silly(`${correlationId} not found in ${collection} - not a timeout`);
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
const { modificationTime, queueItemState: oldState, importJobState = { CREATE: IMPORT_JOB_STATE.EMPTY, UPDATE: IMPORT_JOB_STATE.EMPTY, FIX: IMPORT_JOB_STATE.EMPTY } } = queueItem;
|
|
280
|
+
if (oldState === QUEUE_ITEM_STATE.ABORT || oldState === QUEUE_ITEM_STATE.ERROR || oldState === QUEUE_ITEM_STATE.DONE) {
|
|
281
|
+
logger.silly(`${correlationId} has already state: ${oldState}`);
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
const timeoutTime = new Date(new Date(modificationTime).getTime() + timeoutMinutes * 60000);
|
|
285
|
+
logger.silly(`${correlationId} timeOut @ ${timeoutTime}`);
|
|
286
|
+
if (timeoutTime < new Date()) {
|
|
287
|
+
const finalImportJobStates = [IMPORT_JOB_STATE.ABORT, IMPORT_JOB_STATE.DONE, IMPORT_JOB_STATE.EMPTY, IMPORT_JOB_STATE.ERROR];
|
|
288
|
+
if (!finalImportJobStates.includes(importJobState.CREATE)) {
|
|
289
|
+
await setImportJobState({ correlationId, operation: 'CREATE', importJobState: IMPORT_JOB_STATE.ABORT });
|
|
290
|
+
}
|
|
291
|
+
if (!finalImportJobStates.includes(importJobState.UPDATE)) {
|
|
292
|
+
await setImportJobState({ correlationId, operation: 'UPDATE', importJobState: IMPORT_JOB_STATE.ABORT });
|
|
293
|
+
}
|
|
294
|
+
if (!finalImportJobStates.includes(importJobState.FIX)) {
|
|
295
|
+
await setImportJobState({ correlationId, operation: 'FIX', importJobState: IMPORT_JOB_STATE.ABORT });
|
|
296
|
+
}
|
|
297
|
+
await setState({ correlationId, state: QUEUE_ITEM_STATE.ABORT, errorStatus: httpStatus.REQUEST_TIMEOUT, errorMessage: `Timeout in ${oldState}` });
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
233
300
|
return true;
|
|
234
|
-
}
|
|
235
|
-
} catch (err) {
|
|
236
|
-
if (err instanceof MongoDriverError) {
|
|
237
|
-
debug(err);
|
|
238
|
-
if (err.message.indexOf("File not found for id") !== -1) {
|
|
239
|
-
logger.silly(`mongo/remove: File not found, removing queueItem ${JSON.stringify(clean)} from ${collection}`);
|
|
240
|
-
debug(`mongo/remove: File not found, removing queueItem ${JSON.stringify(clean)} from ${collection}`);
|
|
241
|
-
await operator.deleteOne({ correlationId: clean });
|
|
242
|
-
return true;
|
|
243
|
-
}
|
|
244
|
-
logger.error(err.message);
|
|
245
|
-
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, err.message);
|
|
246
|
-
}
|
|
247
|
-
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, err.message);
|
|
248
301
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
302
|
+
async function remove(params) {
|
|
303
|
+
logger.silly(`${JSON.stringify(params)}`);
|
|
304
|
+
logger.info(`Removing from Mongo (${collection}) id: ${params.correlationId}`);
|
|
305
|
+
debug(`${JSON.stringify(params)}`);
|
|
306
|
+
debug(`Removing from Mongo (${collection}) id: ${params.correlationId}`);
|
|
307
|
+
assertString(params.correlationId, 'correlationId');
|
|
308
|
+
try {
|
|
309
|
+
const removedContent = await removeContent({ correlationId: params.correlationId });
|
|
310
|
+
debug(`removedContent (removeContent result): ${JSON.stringify(removedContent)}`);
|
|
311
|
+
const deleteResult = await operator.deleteOne({ correlationId: params.correlationId });
|
|
312
|
+
debug(`deleteResult: ${JSON.stringify(deleteResult)}`);
|
|
313
|
+
return { removed: deleteResult.deletedCount > 0, deletedContent: removedContent };
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
if (err instanceof MongoDriverError) {
|
|
317
|
+
debug(err);
|
|
318
|
+
if (err.message.indexOf('File not found for id') !== -1) {
|
|
319
|
+
logger.silly(`mongo/remove: File not found, removing queueItem ${JSON.stringify(params.correlationId)} from ${collection}`);
|
|
320
|
+
debug(`mongo/remove: File not found, removing queueItem ${JSON.stringify(params.correlationId)} from ${collection}`);
|
|
321
|
+
const deleteResult = await operator.deleteOne({ correlationId: params.correlationId });
|
|
322
|
+
return { removed: deleteResult.deletedCount > 0, deletedContent: false };
|
|
323
|
+
}
|
|
324
|
+
logger.error(err.message);
|
|
325
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, err.message);
|
|
326
|
+
}
|
|
327
|
+
const driverError = err;
|
|
328
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, driverError.message);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async function readContent(correlationId) {
|
|
332
|
+
logger.info(`Reading content from mongo for id: ${correlationId} in ${collection}`);
|
|
333
|
+
debug(`Reading content from mongo for id: ${correlationId} in ${collection}`);
|
|
334
|
+
assertString(correlationId, 'correlationId');
|
|
335
|
+
const result = await operator.findOne({ correlationId });
|
|
336
|
+
debug(result);
|
|
337
|
+
if (result) {
|
|
338
|
+
const { operationSettings } = result;
|
|
339
|
+
let files = [];
|
|
340
|
+
if (operationSettings.prio === false) {
|
|
341
|
+
files = await gridFSBucket.find({ filename: correlationId }).toArray();
|
|
342
|
+
}
|
|
343
|
+
const hasContent = files.length > 0;
|
|
344
|
+
if (hasContent) {
|
|
345
|
+
return {
|
|
346
|
+
contentType: result.contentType,
|
|
347
|
+
readStream: gridFSBucket.openDownloadStreamByName(correlationId)
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
logger.debug(`OperationSettings for ${correlationId}: ${JSON.stringify(operationSettings)}`);
|
|
351
|
+
debug(`OperationSettings for ${correlationId}: ${JSON.stringify(operationSettings)}`);
|
|
352
|
+
debug(`Content is only available for streamBulk jobs. ${correlationId} is not a streamBulk job.`);
|
|
353
|
+
throw new ApiError(httpStatus.BAD_REQUEST, { message: `Content is only available for streamBulk jobs. ${correlationId} is not a streamBulk job.` });
|
|
354
|
+
}
|
|
355
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `Job ${correlationId} not found.` });
|
|
356
|
+
}
|
|
357
|
+
async function removeContent(params) {
|
|
358
|
+
logger.info(`Removing content from mongo for id: ${params.correlationId} in ${collection}`);
|
|
359
|
+
debug(`Removing content from mongo for id: ${params.correlationId} in ${collection}`);
|
|
360
|
+
assertString(params.correlationId, 'correlationId');
|
|
361
|
+
const result = await gridFSBucket.find({ filename: params.correlationId }).toArray();
|
|
362
|
+
debug(`mongo/removeContent: find bucket result ${JSON.stringify(result)}`);
|
|
363
|
+
if (result.length > 0) {
|
|
364
|
+
const [firstBucketResult] = result;
|
|
365
|
+
const fileId = firstBucketResult._id;
|
|
366
|
+
await gridFSBucket.delete(fileId);
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
logger.debug(`No files for ${params.correlationId} to delete`);
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
async function getOne({ queueItemState, importJobState = undefined }) {
|
|
373
|
+
logger.silly(`queueItemState: ${queueItemState}, importJobState: ${JSON.stringify(importJobState)}`);
|
|
374
|
+
if (queueItemState) {
|
|
375
|
+
assertString(queueItemState, 'queueItemState');
|
|
376
|
+
}
|
|
377
|
+
if (importJobState) {
|
|
378
|
+
assertImportJobStateFilter(importJobState, 'importJobState');
|
|
379
|
+
}
|
|
380
|
+
const cleanQueueItemState = queueItemState ? { queueItemState } : undefined;
|
|
381
|
+
const options = { projection: { _id: 0 } };
|
|
382
|
+
try {
|
|
383
|
+
if (queueItemState && importJobState === undefined) {
|
|
384
|
+
logger.silly(`Checking DB ${collection} for just ${JSON.stringify(queueItemState)}`);
|
|
385
|
+
return operator.findOne({ queueItemState }, options);
|
|
386
|
+
}
|
|
387
|
+
if (importJobState && queueItemState === undefined) {
|
|
388
|
+
logger.silly(`Checking DB ${collection} for ${JSON.stringify(importJobState)}`);
|
|
389
|
+
return operator.findOne({ ...importJobState }, options);
|
|
390
|
+
}
|
|
391
|
+
if (importJobState && queueItemState) {
|
|
392
|
+
logger.silly(`Checking DB ${collection} for ${queueItemState} and ${JSON.stringify(importJobState)}`);
|
|
393
|
+
return operator.findOne({ ...cleanQueueItemState, ...importJobState }, options);
|
|
394
|
+
}
|
|
395
|
+
logger.debug(`getOne not working!`);
|
|
396
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, 'Missing parameters, cannot get queueItem');
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
const apiError = error;
|
|
400
|
+
const errorMessage = apiError.payload || apiError.message || '';
|
|
401
|
+
logError(error);
|
|
402
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async function getStream(correlationId) {
|
|
406
|
+
logger.info(`Forming stream from mongo for ${correlationId} in ${collection}`);
|
|
407
|
+
assertString(correlationId, 'correlationId');
|
|
408
|
+
try {
|
|
409
|
+
const files = await gridFSBucket.find({ filename: correlationId }).toArray();
|
|
410
|
+
if (files.length === 0) {
|
|
411
|
+
logger.info(`getStream: file ${correlationId} not found in ${collection}`);
|
|
412
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `File ${correlationId} not found in ${collection}` });
|
|
413
|
+
}
|
|
414
|
+
return gridFSBucket.openDownloadStreamByName(correlationId);
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
if (error instanceof ApiError) {
|
|
418
|
+
throw error;
|
|
419
|
+
}
|
|
420
|
+
const apiError = error;
|
|
421
|
+
const errorMessage = apiError.payload || apiError.message || '';
|
|
422
|
+
logError(error);
|
|
423
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async function pushIds({ correlationId, handledIds, rejectedIds }) {
|
|
427
|
+
if (!Array.isArray(handledIds) || !Array.isArray(rejectedIds)) {
|
|
428
|
+
throw new ApiError(httpStatus.BAD_REQUEST, 'pushIds: handledIds and rejectedIds must be arrays');
|
|
429
|
+
}
|
|
430
|
+
assertString(correlationId, 'correlationId');
|
|
431
|
+
logger.verbose(`Push ids (${handledIds.length}) and rejectedIds (${rejectedIds.length}) ${correlationId} to ${collection}`);
|
|
432
|
+
logger.debug(`ids (${handledIds.length}): ${JSON.stringify(handledIds)}, rejectedIds ${rejectedIds.length}: ${JSON.stringify(rejectedIds)}`);
|
|
433
|
+
try {
|
|
434
|
+
await operator.updateOne({
|
|
435
|
+
correlationId
|
|
436
|
+
}, {
|
|
437
|
+
$set: {
|
|
438
|
+
modificationTime: new Date()
|
|
439
|
+
},
|
|
440
|
+
$push: {
|
|
441
|
+
handledIds: { $each: handledIds },
|
|
442
|
+
rejectedIds: { $each: rejectedIds }
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
const apiError = error;
|
|
448
|
+
const errorMessage = apiError.payload || apiError.message || '';
|
|
449
|
+
logError(error);
|
|
450
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
async function pushMessages({ correlationId, messages, messageField = 'messages' }) {
|
|
454
|
+
if (!Array.isArray(messages)) {
|
|
455
|
+
throw new ApiError(httpStatus.BAD_REQUEST, 'pushMessages: messages must be an array');
|
|
456
|
+
}
|
|
457
|
+
assertString(correlationId, 'correlationId');
|
|
458
|
+
assertString(messageField, 'messageField');
|
|
459
|
+
logger.verbose(`Push messages (${messages.length}) to ${messageField} ${correlationId} to ${collection}`);
|
|
460
|
+
logger.silly(`Messages (${messages.length}): ${JSON.stringify(messages)}`);
|
|
461
|
+
try {
|
|
462
|
+
await operator.updateOne({
|
|
463
|
+
correlationId
|
|
464
|
+
}, {
|
|
465
|
+
$set: {
|
|
466
|
+
modificationTime: new Date()
|
|
467
|
+
},
|
|
468
|
+
$push: {
|
|
469
|
+
[messageField]: { $each: messages }
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
const apiError = error;
|
|
475
|
+
const errorMessage = apiError.payload || apiError.message || '';
|
|
476
|
+
logError(error);
|
|
477
|
+
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
function setState({ correlationId, state, errorMessage = undefined, errorStatus = undefined }) {
|
|
481
|
+
assertString(correlationId, 'correlationId');
|
|
482
|
+
const errorString = errorMessage || errorStatus ? `, Error message: '${JSON.stringify(errorMessage) || ''}', Error status: '${errorStatus || ''}'` : '';
|
|
483
|
+
logger.info(`Setting queue-item state ${state} for ${correlationId}${errorString} to ${collection}`);
|
|
484
|
+
const allQueueItemStates = [
|
|
485
|
+
QUEUE_ITEM_STATE.DONE,
|
|
486
|
+
QUEUE_ITEM_STATE.ERROR,
|
|
487
|
+
QUEUE_ITEM_STATE.ABORT,
|
|
488
|
+
...Object.values(QUEUE_ITEM_STATE.VALIDATOR),
|
|
489
|
+
...Object.values(QUEUE_ITEM_STATE.IMPORTER)
|
|
490
|
+
];
|
|
491
|
+
if (!allQueueItemStates.includes(state)) {
|
|
492
|
+
debug(`Trying to set invalid state ${state}`);
|
|
493
|
+
throw new ApiError(httpStatus.BAD_REQUEST, 'Trying to set invalid state');
|
|
494
|
+
}
|
|
495
|
+
const updateValues = {
|
|
496
|
+
queueItemState: state,
|
|
497
|
+
modificationTime: new Date(),
|
|
498
|
+
errorMessage,
|
|
499
|
+
errorStatus
|
|
263
500
|
};
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
debug(`Content is only available for streamBulk jobs. ${correlationId} is not a streamBulk job.`);
|
|
268
|
-
throw new ApiError(httpStatus.BAD_REQUEST, { message: `Content is only available for streamBulk jobs. ${correlationId} is not a streamBulk job.` });
|
|
501
|
+
Object.keys(updateValues).forEach(key => updateValues[key] === undefined && delete updateValues[key]);
|
|
502
|
+
return operator
|
|
503
|
+
.findOneAndUpdate({ correlationId }, { $set: updateValues }, { projection: { _id: 0 }, returnDocument: 'after' });
|
|
269
504
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
505
|
+
function setImportJobState({ correlationId, operation, importJobState }) {
|
|
506
|
+
assertString(correlationId, 'correlationId');
|
|
507
|
+
logger.info(`Setting queue-item importJobState: {${operation}: ${importJobState}} for ${correlationId}`);
|
|
508
|
+
debug(`Setting queue-item importJobState: {${operation}: ${importJobState}} for ${correlationId}`);
|
|
509
|
+
if (!(operation in OPERATIONS)) {
|
|
510
|
+
debug(`Error: ${operation} is not in ${JSON.stringify(OPERATIONS)}`);
|
|
511
|
+
throw new ApiError(httpStatus.BAD_REQUEST, 'Invalid operation for import job state');
|
|
512
|
+
}
|
|
513
|
+
if (!(importJobState in IMPORT_JOB_STATE)) {
|
|
514
|
+
debug(`Error: ${importJobState} is not in ${JSON.stringify(IMPORT_JOB_STATE)}`);
|
|
515
|
+
throw new ApiError(httpStatus.BAD_REQUEST, 'Invalid import job state');
|
|
516
|
+
}
|
|
517
|
+
const newJobState = getNewJobState(operation, importJobState);
|
|
518
|
+
return operator.findOneAndUpdate({
|
|
519
|
+
correlationId
|
|
520
|
+
}, {
|
|
521
|
+
$set: {
|
|
522
|
+
...newJobState,
|
|
523
|
+
modificationTime: new Date()
|
|
524
|
+
}
|
|
525
|
+
}, { projection: { _id: 0 }, returnDocument: 'after' });
|
|
283
526
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
if (importJobState && queueItemState === void 0) {
|
|
297
|
-
logger.silly(`Checking DB ${collection} for ${JSON.stringify(importJobState)}`);
|
|
298
|
-
return operator.findOne({ ...importJobState }, options);
|
|
299
|
-
}
|
|
300
|
-
if (importJobState && queueItemState) {
|
|
301
|
-
logger.silly(`Checking DB ${collection} for ${queueItemState} and ${JSON.stringify(importJobState)}`);
|
|
302
|
-
return operator.findOne({ ...cleanQueueItemState, ...importJobState }, options);
|
|
303
|
-
}
|
|
304
|
-
logger.debug(`getOne not working!`);
|
|
305
|
-
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, "Missing parameters, cannot get queueItem");
|
|
306
|
-
} catch (error) {
|
|
307
|
-
const errorMessage = error.payload || error.message || "";
|
|
308
|
-
logError(error);
|
|
309
|
-
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
527
|
+
function getNewJobState(operation, importJobState) {
|
|
528
|
+
if (operation === OPERATIONS.CREATE) {
|
|
529
|
+
return { 'importJobState.CREATE': importJobState };
|
|
530
|
+
}
|
|
531
|
+
if (operation === OPERATIONS.UPDATE) {
|
|
532
|
+
return { 'importJobState.UPDATE': importJobState };
|
|
533
|
+
}
|
|
534
|
+
if (operation === OPERATIONS.FIX) {
|
|
535
|
+
return { 'importJobState.FIX': importJobState };
|
|
536
|
+
}
|
|
537
|
+
throw new ApiError(httpStatus.BAD_REQUEST, 'Invalid operation for import job state');
|
|
310
538
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
} catch (error) {
|
|
318
|
-
const errorMessage = error.payload || error.message || "";
|
|
319
|
-
logError(error);
|
|
320
|
-
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Mongo errored: ${errorMessage}`);
|
|
539
|
+
function unwrapAndUpdateResult(result, correlationId) {
|
|
540
|
+
if (result === null || result === undefined) {
|
|
541
|
+
logger.info(`Queue item ${correlationId} not found in ${collection}`);
|
|
542
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `Job ${correlationId} not found.` });
|
|
543
|
+
}
|
|
544
|
+
return result;
|
|
321
545
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const clean = sanitize(correlationId);
|
|
343
|
-
const cleanMessageField = sanitize(messageField);
|
|
344
|
-
debug(`${messageField} -> ${cleanMessageField}`);
|
|
345
|
-
await operator.updateOne({
|
|
346
|
-
correlationId: clean
|
|
347
|
-
}, {
|
|
348
|
-
$set: {
|
|
349
|
-
modificationTime: moment().toDate()
|
|
350
|
-
},
|
|
351
|
-
$push: {
|
|
352
|
-
[cleanMessageField]: { $each: messages }
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
function setState({ correlationId, state, errorMessage = void 0, errorStatus = void 0 }) {
|
|
357
|
-
const errorString = errorMessage || errorStatus ? `, Error message: '${JSON.stringify(errorMessage) || ""}', Error status: '${errorStatus || ""}'` : "";
|
|
358
|
-
logger.info(`Setting queue-item state ${state} for ${correlationId}${errorString} to ${collection}`);
|
|
359
|
-
const stateInQueueItemStates = Object.values(QUEUE_ITEM_STATE).indexOf(state) > -1;
|
|
360
|
-
const stateInQueueItemStatesValidator = Object.values(QUEUE_ITEM_STATE.VALIDATOR).indexOf(state) > -1;
|
|
361
|
-
const stateInQueueItemStatesImporter = Object.values(QUEUE_ITEM_STATE.IMPORTER).indexOf(state) > -1;
|
|
362
|
-
if (!stateInQueueItemStates && !stateInQueueItemStatesValidator && !stateInQueueItemStatesImporter) {
|
|
363
|
-
debug(`Trying to set invalid state ${state}`);
|
|
364
|
-
throw new ApiError(httpStatus.BAD_REQUEST, "Trying to set invalid state");
|
|
546
|
+
async function setOperation({ correlationId, operation }) {
|
|
547
|
+
assertString(correlationId, 'correlationId');
|
|
548
|
+
const newOperation = operation;
|
|
549
|
+
const existing = await operator.findOne({ correlationId });
|
|
550
|
+
if (!existing) {
|
|
551
|
+
logger.info(`Setting queue-item operation: queue item ${correlationId} not found in ${collection}`);
|
|
552
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `Job ${correlationId} not found.` });
|
|
553
|
+
}
|
|
554
|
+
const { operation: oldOperation } = existing;
|
|
555
|
+
logger.info(`Setting queue-item operation from ${oldOperation} to ${newOperation} for ${correlationId} to ${collection}`);
|
|
556
|
+
const result = await operator.findOneAndUpdate({
|
|
557
|
+
correlationId
|
|
558
|
+
}, {
|
|
559
|
+
$set: {
|
|
560
|
+
operation: newOperation,
|
|
561
|
+
modificationTime: new Date()
|
|
562
|
+
}
|
|
563
|
+
}, { projection: { _id: 0 }, returnDocument: 'after' });
|
|
564
|
+
debugDev(`${JSON.stringify(result)}`);
|
|
565
|
+
return unwrapAndUpdateResult(result, correlationId);
|
|
365
566
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
567
|
+
async function setOperations({ correlationId, addOperation, removeOperation = undefined }) {
|
|
568
|
+
assertString(correlationId, 'correlationId');
|
|
569
|
+
const queueItem = await operator.findOne({ correlationId });
|
|
570
|
+
logger.silly(`We found a queueItem: ${JSON.stringify(queueItem)}`);
|
|
571
|
+
if (!queueItem) {
|
|
572
|
+
logger.info(`Setting queue-item operations: queue item ${correlationId} not found in ${collection}`);
|
|
573
|
+
throw new ApiError(httpStatus.NOT_FOUND, { message: `Job ${correlationId} not found.` });
|
|
574
|
+
}
|
|
575
|
+
const oldOperations = queueItem.operations;
|
|
576
|
+
logger.info(`Setting queue-item operations from ${JSON.stringify(oldOperations)} by adding ${addOperation} and removing ${removeOperation} for ${correlationId} to ${collection}`);
|
|
577
|
+
const operationsAfterRemove = oldOperations.filter(operation => operation !== removeOperation);
|
|
578
|
+
const operationsAfterRemoveAndAdd = operationsAfterRemove.includes(addOperation) ? operationsAfterRemove : [...operationsAfterRemove, addOperation];
|
|
579
|
+
logger.silly(`operationsAfterRemove: ${operationsAfterRemove}`);
|
|
580
|
+
logger.silly(`operationAfterRemoveAndAdd: ${operationsAfterRemoveAndAdd}`);
|
|
581
|
+
const result = await operator.findOneAndUpdate({
|
|
582
|
+
correlationId
|
|
583
|
+
}, {
|
|
584
|
+
$set: {
|
|
585
|
+
operations: operationsAfterRemoveAndAdd,
|
|
586
|
+
modificationTime: new Date()
|
|
587
|
+
}
|
|
588
|
+
}, { projection: { _id: 0 }, returnDocument: 'after' });
|
|
589
|
+
debugDev(`${JSON.stringify(result)}`);
|
|
590
|
+
return unwrapAndUpdateResult(result, correlationId);
|
|
388
591
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
592
|
+
async function addBlobSize({ correlationId }) {
|
|
593
|
+
assertString(correlationId, 'correlationId');
|
|
594
|
+
const result = await operator.findOneAndUpdate({
|
|
595
|
+
correlationId,
|
|
596
|
+
queueItemState: QUEUE_ITEM_STATE.VALIDATOR.WAITING_FOR_RECORDS
|
|
597
|
+
}, {
|
|
598
|
+
$inc: {
|
|
599
|
+
blobSize: 1
|
|
600
|
+
},
|
|
601
|
+
$set: {
|
|
602
|
+
modificationTime: new Date()
|
|
603
|
+
}
|
|
604
|
+
}, { projection: { _id: 0 }, returnDocument: 'after' });
|
|
605
|
+
logger.verbose(`AddBlobSizeResult in mongo: ${JSON.stringify(result)}`);
|
|
606
|
+
debugDev(`${JSON.stringify(result)}`);
|
|
607
|
+
return result;
|
|
392
608
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
609
|
+
async function setBlobSize({ correlationId, blobSize }) {
|
|
610
|
+
assertString(correlationId, 'correlationId');
|
|
611
|
+
assertNumber(blobSize, 'blobSize');
|
|
612
|
+
const result = await operator.findOneAndUpdate({
|
|
613
|
+
correlationId
|
|
614
|
+
}, {
|
|
615
|
+
$set: {
|
|
616
|
+
blobSize,
|
|
617
|
+
modificationTime: new Date()
|
|
618
|
+
}
|
|
619
|
+
}, { projection: { _id: 0 }, returnDocument: 'after' });
|
|
620
|
+
logger.verbose(`SetBlobSizeResult in mongo: ${JSON.stringify(result)}`);
|
|
621
|
+
debugDev(`${JSON.stringify(result)}`);
|
|
622
|
+
return result;
|
|
405
623
|
}
|
|
406
|
-
return operator.findOneAndUpdate({
|
|
407
|
-
correlationId: cleanCorrelationId
|
|
408
|
-
}, {
|
|
409
|
-
$set: {
|
|
410
|
-
...newJobState,
|
|
411
|
-
modificationTime: moment().toDate()
|
|
412
|
-
}
|
|
413
|
-
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
414
|
-
}
|
|
415
|
-
async function setOperation({ correlationId, operation }) {
|
|
416
|
-
const newOperation = operation;
|
|
417
|
-
const { operation: oldOperation } = await operator.findOne({ correlationId });
|
|
418
|
-
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
|
-
const result = await operator.findOneAndUpdate({
|
|
422
|
-
correlationId: cleanCorrelationId
|
|
423
|
-
}, {
|
|
424
|
-
$set: {
|
|
425
|
-
operation: cleanNewOperation,
|
|
426
|
-
modificationTime: moment().toDate()
|
|
427
|
-
}
|
|
428
|
-
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
429
|
-
debugDev(`${JSON.stringify(result)}`);
|
|
430
|
-
return result.ok || result;
|
|
431
|
-
}
|
|
432
|
-
async function setOperations({ correlationId, addOperation, removeOperation = void 0 }) {
|
|
433
|
-
const cleanCorrelationId = sanitize(correlationId);
|
|
434
|
-
const queueItem = await operator.findOne({ correlationId: cleanCorrelationId });
|
|
435
|
-
logger.silly(`We found a queueItem: ${JSON.stringify(queueItem)}`);
|
|
436
|
-
const oldOperations = queueItem.operations;
|
|
437
|
-
logger.info(`Setting queue-item operations from ${JSON.stringify(oldOperations)} by adding ${addOperation} and removing ${removeOperation} for ${correlationId} to ${collection}`);
|
|
438
|
-
const operationsAfterRemove = oldOperations.filter((operation) => operation !== removeOperation);
|
|
439
|
-
const operationsAfterRemoveAndAdd = operationsAfterRemove.includes(addOperation) ? operationsAfterRemove : [...operationsAfterRemove, addOperation];
|
|
440
|
-
logger.silly(`operationsAfterRemove: ${operationsAfterRemove}`);
|
|
441
|
-
logger.silly(`operationAfterRemoveAndAdd: ${operationsAfterRemoveAndAdd}`);
|
|
442
|
-
const result = await operator.findOneAndUpdate({
|
|
443
|
-
correlationId: cleanCorrelationId
|
|
444
|
-
}, {
|
|
445
|
-
$set: {
|
|
446
|
-
operations: operationsAfterRemoveAndAdd,
|
|
447
|
-
modificationTime: moment().toDate()
|
|
448
|
-
}
|
|
449
|
-
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
450
|
-
debugDev(`${JSON.stringify(result)}`);
|
|
451
|
-
return result.ok || result;
|
|
452
|
-
}
|
|
453
|
-
async function addBlobSize({ correlationId }) {
|
|
454
|
-
const cleanCorrelationId = sanitize(correlationId);
|
|
455
|
-
const result = await operator.findOneAndUpdate({
|
|
456
|
-
correlationId: cleanCorrelationId,
|
|
457
|
-
queueItemState: QUEUE_ITEM_STATE.VALIDATOR.WAITING_FOR_RECORDS
|
|
458
|
-
}, {
|
|
459
|
-
$inc: {
|
|
460
|
-
blobSize: 1
|
|
461
|
-
},
|
|
462
|
-
$set: {
|
|
463
|
-
modificationTime: moment().toDate()
|
|
464
|
-
}
|
|
465
|
-
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
466
|
-
logger.verbose(`AddBlobSizeResult in mongo: ${JSON.stringify(result)}`);
|
|
467
|
-
debugDev(`${JSON.stringify(result)}`);
|
|
468
|
-
return result;
|
|
469
|
-
}
|
|
470
|
-
async function setBlobSize({ correlationId, blobSize }) {
|
|
471
|
-
const cleanCorrelationId = sanitize(correlationId);
|
|
472
|
-
const cleanBlobSize = sanitize(blobSize);
|
|
473
|
-
const result = await operator.findOneAndUpdate({
|
|
474
|
-
correlationId: cleanCorrelationId
|
|
475
|
-
}, {
|
|
476
|
-
$set: {
|
|
477
|
-
blobSize: cleanBlobSize,
|
|
478
|
-
modificationTime: moment().toDate()
|
|
479
|
-
}
|
|
480
|
-
}, { projection: { _id: 0 }, returnDocument: "after" });
|
|
481
|
-
logger.verbose(`SetBlobSizeResult in mongo: ${JSON.stringify(result)}`);
|
|
482
|
-
debugDev(`${JSON.stringify(result)}`);
|
|
483
|
-
return result;
|
|
484
|
-
}
|
|
485
624
|
}
|
|
486
|
-
//# sourceMappingURL=mongo.js.map
|
|
625
|
+
//# sourceMappingURL=mongo.js.map
|