@izara_project/izara-core-library-asynchronous-flow 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +58 -0
- package/package.json +7 -5
- package/src/AsyncFlowSharedLib.js +866 -0
package/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2021 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
// Import the Asynchronous Flow shared library functions
|
|
21
|
+
const asyncFlowSharedLib = require('./src/AsyncFlowSharedLib');
|
|
22
|
+
|
|
23
|
+
// Export all the functions
|
|
24
|
+
module.exports = {
|
|
25
|
+
// Identifier creation
|
|
26
|
+
createFieldNameUniqueRequestId: asyncFlowSharedLib.createFieldNameUniqueRequestId,
|
|
27
|
+
createConcatenatedAwaitingStepId: asyncFlowSharedLib.createConcatenatedAwaitingStepId,
|
|
28
|
+
createConcatenatedPendingStepId: asyncFlowSharedLib.createConcatenatedPendingStepId,
|
|
29
|
+
createAwaitingStepId: asyncFlowSharedLib.createAwaitingStepId,
|
|
30
|
+
createPendingStepId: asyncFlowSharedLib.createPendingStepId,
|
|
31
|
+
explodePendingStepId: asyncFlowSharedLib.explodePendingStepId,
|
|
32
|
+
|
|
33
|
+
// Awaiting Multiple Steps
|
|
34
|
+
createAwaitingMultipleStepsWithAdditionalAttributes: asyncFlowSharedLib.createAwaitingMultipleStepsWithAdditionalAttributes,
|
|
35
|
+
createAwaitingMultipleSteps: asyncFlowSharedLib.createAwaitingMultipleSteps,
|
|
36
|
+
|
|
37
|
+
// Awaiting Step
|
|
38
|
+
createAwaitingStep: asyncFlowSharedLib.createAwaitingStep,
|
|
39
|
+
findPendingStepIdsAwaitingStep: asyncFlowSharedLib.findPendingStepIdsAwaitingStep,
|
|
40
|
+
findPendingStepsAwaitingStep: asyncFlowSharedLib.findPendingStepsAwaitingStep,
|
|
41
|
+
|
|
42
|
+
// Checking and clearing steps
|
|
43
|
+
checkAllAwaitingStepsFinished: asyncFlowSharedLib.checkAllAwaitingStepsFinished,
|
|
44
|
+
clearAllAwaitingSteps: asyncFlowSharedLib.clearAllAwaitingSteps,
|
|
45
|
+
removeAwaitingStep: asyncFlowSharedLib.removeAwaitingStep,
|
|
46
|
+
removeAwaitingMultipleStep: asyncFlowSharedLib.removeAwaitingMultipleStep,
|
|
47
|
+
removeAwaitingStepWithCheckUniqueRequestId: asyncFlowSharedLib.removeAwaitingStepWithCheckUniqueRequestId,
|
|
48
|
+
|
|
49
|
+
// Request and cache processing
|
|
50
|
+
checkUniqueRequestProcessing: asyncFlowSharedLib.checkUniqueRequestProcessing,
|
|
51
|
+
checkTimeCacheComplete: asyncFlowSharedLib.checkTimeCacheComplete,
|
|
52
|
+
checkAndGetTimeCacheComplete: asyncFlowSharedLib.checkAndGetTimeCacheComplete,
|
|
53
|
+
checkCacheUniqueRequestId: asyncFlowSharedLib.checkCacheUniqueRequestId,
|
|
54
|
+
|
|
55
|
+
// Pagination and invocation helpers
|
|
56
|
+
validateStartKeyParam: asyncFlowSharedLib.validateStartKeyParam,
|
|
57
|
+
validateMultipleInvocations: asyncFlowSharedLib.validateMultipleInvocations
|
|
58
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@izara_project/izara-core-library-asynchronous-flow",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Shared asynchronous flow logic",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -20,9 +20,11 @@
|
|
|
20
20
|
"testEnvironment": "node"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"@izara_project/izara-core-library-core": "^1.0.16",
|
|
24
|
+
"@izara_project/izara-core-library-dynamodb": "^1.0.2",
|
|
23
25
|
"@izara_project/izara-core-library-external-request": "^1.0.17",
|
|
24
|
-
"@izara_project/izara-core-library-
|
|
25
|
-
"@izara_project/izara-
|
|
26
|
-
"
|
|
26
|
+
"@izara_project/izara-core-library-logger": "^1.0.6",
|
|
27
|
+
"@izara_project/izara-core-library-sqs": "^1.0.2",
|
|
28
|
+
"@izara_project/izara-core-library-trigger-cache": "^1.0.2"
|
|
27
29
|
}
|
|
28
|
-
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2021 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
// Core libraries
|
|
21
|
+
const { NoRetryError } = require('@izara_project/izara-core-library-core');
|
|
22
|
+
const Logger = require('@izara_project/izara-core-library-logger');
|
|
23
|
+
|
|
24
|
+
// Data and service interaction libraries
|
|
25
|
+
const dynamodbSharedLib = require('@izara_project/izara-core-library-dynamodb');
|
|
26
|
+
const sqsSharedLib = require('@izara_project/izara-core-library-sqs');
|
|
27
|
+
const triggeredCacheSharedLib = require('@izara_project/izara-core-library-trigger-cache');
|
|
28
|
+
|
|
29
|
+
// External service interactions
|
|
30
|
+
const { sqs } = require('@izara_project/izara-core-library-external-request');
|
|
31
|
+
|
|
32
|
+
module.exports.createFieldNameUniqueRequestId = (
|
|
33
|
+
prefix,
|
|
34
|
+
uniqueRequestIdFieldName = 'UniqueRequestId'
|
|
35
|
+
) => {
|
|
36
|
+
return prefix + uniqueRequestIdFieldName;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports.createConcatenatedAwaitingStepId = (
|
|
40
|
+
partitionKey,
|
|
41
|
+
sortId,
|
|
42
|
+
prefix = ""
|
|
43
|
+
) => {
|
|
44
|
+
return prefix + partitionKey + "_" + sortId
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports.createConcatenatedPendingStepId = (
|
|
48
|
+
parentId,
|
|
49
|
+
childId
|
|
50
|
+
) => {
|
|
51
|
+
return parentId + "_" + childId
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports.createAwaitingStepId = (
|
|
55
|
+
partitionKey,
|
|
56
|
+
prefix = ""
|
|
57
|
+
) => {
|
|
58
|
+
return prefix + partitionKey
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports.createPendingStepId = (
|
|
62
|
+
identifierId,
|
|
63
|
+
prefix = ""
|
|
64
|
+
) => {
|
|
65
|
+
return prefix + identifierId
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports.explodePendingStepId = (
|
|
69
|
+
pendingStepId,
|
|
70
|
+
prefix = ""
|
|
71
|
+
) => {
|
|
72
|
+
if (prefix === "") {
|
|
73
|
+
return pendingStepId;
|
|
74
|
+
} else {
|
|
75
|
+
let identifierId = pendingStepId.slice(prefix.length)
|
|
76
|
+
// ** validate identifierId == prefix
|
|
77
|
+
if (identifierId == prefix) {
|
|
78
|
+
throw new NoRetryError("IdentifierId should not be like prefix.");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Logger.debug("return explode:", identifierId);
|
|
82
|
+
return identifierId;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//====================================== AwaitingMultipleSteps
|
|
88
|
+
// AwaitingMultipleSteps is when a flow is awaiting multiple external flows before it can continue
|
|
89
|
+
// One awaitingStepId can have multiple pendingStepIds that are awaiting it
|
|
90
|
+
// One pendingStepId can have multiple awaitingStepIds it is awaiting
|
|
91
|
+
// logic can prepend any prefix to awaitingStepId if want to be share one table and differentiate different external step ids
|
|
92
|
+
|
|
93
|
+
//not yet used ?
|
|
94
|
+
module.exports.createAwaitingMultipleStepsWithAdditionalAttributes = async (
|
|
95
|
+
_izContext,
|
|
96
|
+
records, // array of object including properties: awaitingStepId / (optional) additionalAttributes
|
|
97
|
+
pendingStepId,
|
|
98
|
+
tableName = "AwaitingMultipleSteps",
|
|
99
|
+
byPendingTableName = "AwaitingMultipleStepByPending"
|
|
100
|
+
) => {
|
|
101
|
+
_izContext.logger.debug("Lib:createAwaitingMultipleStepsWithAdditionalAttributes", {
|
|
102
|
+
records: records,
|
|
103
|
+
pendingStepId: pendingStepId,
|
|
104
|
+
tableName: tableName,
|
|
105
|
+
byPendingTableName: byPendingTableName
|
|
106
|
+
});
|
|
107
|
+
let promiseArray = []
|
|
108
|
+
|
|
109
|
+
for (let record of records) {
|
|
110
|
+
|
|
111
|
+
let attributesWhenCreate = {
|
|
112
|
+
awaitingStepId: record.awaitingStepId,
|
|
113
|
+
pendingStepId: pendingStepId,
|
|
114
|
+
timestamp: Date.now(),
|
|
115
|
+
...record.additionalAttributes
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
promiseArray.push(
|
|
119
|
+
dynamodbSharedLib.putItem(
|
|
120
|
+
_izContext,
|
|
121
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
122
|
+
attributesWhenCreate
|
|
123
|
+
)
|
|
124
|
+
);
|
|
125
|
+
promiseArray.push(
|
|
126
|
+
dynamodbSharedLib.putItem(
|
|
127
|
+
_izContext,
|
|
128
|
+
await dynamodbSharedLib.tableName(_izContext, byPendingTableName),
|
|
129
|
+
{
|
|
130
|
+
pendingStepId: pendingStepId,
|
|
131
|
+
awaitingStepId: record.awaitingStepId,
|
|
132
|
+
timestamp: Date.now(),
|
|
133
|
+
}
|
|
134
|
+
));
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
await Promise.all(promiseArray);
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports.createAwaitingMultipleSteps = async (
|
|
143
|
+
_izContext,
|
|
144
|
+
records, // array of awaitingStepIds
|
|
145
|
+
pendingStepId,
|
|
146
|
+
tableName = "AwaitingMultipleSteps",
|
|
147
|
+
byPendingTableName = "AwaitingMultipleStepByPending"
|
|
148
|
+
) => {
|
|
149
|
+
_izContext.logger.debug("Lib:createAwaitingMultipleSteps", {
|
|
150
|
+
records: records,
|
|
151
|
+
pendingStepId: pendingStepId,
|
|
152
|
+
tableName: tableName,
|
|
153
|
+
byPendingTableName: byPendingTableName
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// // 0001 ORG.
|
|
157
|
+
let promiseArray = []
|
|
158
|
+
|
|
159
|
+
for (let record of records) {
|
|
160
|
+
|
|
161
|
+
let attributesWhenCreate = {
|
|
162
|
+
awaitingStepId: record,
|
|
163
|
+
pendingStepId: pendingStepId,
|
|
164
|
+
timestamp: Date.now()
|
|
165
|
+
}
|
|
166
|
+
_izContext.logger.debug("putItem:AwaitingMultipleSteps +++++++", { awaitingStepId: attributesWhenCreate.awaitingStepId })
|
|
167
|
+
promiseArray.push(
|
|
168
|
+
dynamodbSharedLib.putItem(
|
|
169
|
+
_izContext,
|
|
170
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
171
|
+
attributesWhenCreate
|
|
172
|
+
)
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
_izContext.logger.debug("putItem:AwaitingMultipleStepByPending", { awaitingStepId: attributesWhenCreate.awaitingStepId })
|
|
177
|
+
promiseArray.push(
|
|
178
|
+
dynamodbSharedLib.putItem(
|
|
179
|
+
_izContext,
|
|
180
|
+
await dynamodbSharedLib.tableName(_izContext, byPendingTableName),
|
|
181
|
+
attributesWhenCreate
|
|
182
|
+
)
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
_izContext.logger.debug("check 0")
|
|
186
|
+
|
|
187
|
+
}
|
|
188
|
+
await Promise.all(promiseArray);
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//====================================== AwaitingStep //======================================
|
|
193
|
+
// AwaitingStep is when a flow is awaiting one external flow, and will continue it's flow once that one external flow is complete
|
|
194
|
+
// One awaitingStepId can have multiple pendingStepIds that are awaiting it
|
|
195
|
+
// logic can prepend any prefix to awaitingStepId if want to be share one table and differentiate different external step ids
|
|
196
|
+
|
|
197
|
+
module.exports.createAwaitingStep = async (
|
|
198
|
+
_izContext,
|
|
199
|
+
awaitingStepId,
|
|
200
|
+
pendingStepId,
|
|
201
|
+
tableName = "AwaitingStep",
|
|
202
|
+
additionalAttributes = {} // save in top level
|
|
203
|
+
) => {
|
|
204
|
+
|
|
205
|
+
let attributesWhenCreate = {
|
|
206
|
+
awaitingStepId: awaitingStepId,
|
|
207
|
+
pendingStepId: pendingStepId,
|
|
208
|
+
timestamp: Date.now(),
|
|
209
|
+
uniqueRequestId: _izContext.uniqueRequestId,
|
|
210
|
+
}
|
|
211
|
+
// loop if not empty
|
|
212
|
+
for (let additionalAttribute in additionalAttributes) {
|
|
213
|
+
attributesWhenCreate[additionalAttribute] = additionalAttributes[additionalAttribute]
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
await dynamodbSharedLib.putItem(
|
|
217
|
+
_izContext,
|
|
218
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
219
|
+
attributesWhenCreate
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
module.exports.findPendingStepIdsAwaitingStep = async (
|
|
227
|
+
_izContext,
|
|
228
|
+
awaitingStepId,
|
|
229
|
+
tableName = "AwaitingStep"
|
|
230
|
+
) => {
|
|
231
|
+
|
|
232
|
+
let pendingStepIds = [];
|
|
233
|
+
|
|
234
|
+
let listPendingStepIds = await dynamodbSharedLib.query(
|
|
235
|
+
_izContext,
|
|
236
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
237
|
+
{
|
|
238
|
+
awaitingStepId: awaitingStepId
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
for (let idx = 0; idx < listPendingStepIds.Items.length; idx++) {
|
|
243
|
+
pendingStepIds.push(listPendingStepIds.Items[idx].pendingStepId)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return pendingStepIds
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
module.exports.findPendingStepsAwaitingStep = async (
|
|
250
|
+
_izContext,
|
|
251
|
+
awaitingStepId,
|
|
252
|
+
tableName = "AwaitingStep"
|
|
253
|
+
) => {
|
|
254
|
+
|
|
255
|
+
let listPendingSteps = await dynamodbSharedLib.query(
|
|
256
|
+
_izContext,
|
|
257
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
258
|
+
{
|
|
259
|
+
awaitingStepId: awaitingStepId
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
_izContext.logger.debug("Record of awaitingStepId", listPendingSteps)
|
|
263
|
+
return listPendingSteps.Items;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
module.exports.checkAllAwaitingStepsFinished = async (
|
|
269
|
+
_izContext,
|
|
270
|
+
pendingStepId,
|
|
271
|
+
currentAwaitingStepId = null,
|
|
272
|
+
tableName = 'AwaitingMultipleSteps',
|
|
273
|
+
byPendingTableName = "AwaitingMultipleStepByPending"
|
|
274
|
+
// indexName = ''
|
|
275
|
+
) => {
|
|
276
|
+
_izContext.logger.debug("Lib:checkAllAwaitingStepsFinished", {
|
|
277
|
+
pendingStepId: pendingStepId,
|
|
278
|
+
currentAwaitingStepId: currentAwaitingStepId,
|
|
279
|
+
tableName: tableName,
|
|
280
|
+
byPendingTableName: byPendingTableName
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
if (currentAwaitingStepId) {
|
|
284
|
+
|
|
285
|
+
//* not need to save complete in AwaitingMultipleSteps Table but save in AwaitingMultipleStepByPending
|
|
286
|
+
// await dynamodbSharedLib.updateItem(
|
|
287
|
+
// _izContext,
|
|
288
|
+
// dynamodbSharedLib.tableName(tableName),
|
|
289
|
+
// {
|
|
290
|
+
// awaitingStepId: currentAwaitingStepId,
|
|
291
|
+
// pendingStepId: pendingStepId
|
|
292
|
+
// },
|
|
293
|
+
// {
|
|
294
|
+
// complete: true
|
|
295
|
+
// },
|
|
296
|
+
// )
|
|
297
|
+
|
|
298
|
+
_izContext.logger.debug(`---- update ${byPendingTableName} table ----`);
|
|
299
|
+
await dynamodbSharedLib.updateItem(
|
|
300
|
+
_izContext,
|
|
301
|
+
await dynamodbSharedLib.tableName(_izContext, byPendingTableName),
|
|
302
|
+
{
|
|
303
|
+
pendingStepId: pendingStepId,
|
|
304
|
+
awaitingStepId: currentAwaitingStepId
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
complete: true
|
|
308
|
+
},
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
}
|
|
312
|
+
let listPendingStepIds = await dynamodbSharedLib.query(
|
|
313
|
+
_izContext,
|
|
314
|
+
await dynamodbSharedLib.tableName(_izContext, byPendingTableName),
|
|
315
|
+
{
|
|
316
|
+
pendingStepId: pendingStepId
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
limit: 50 // arbritrary limit so not pull too many results, need >2 because some others might be marked as "complete" = true
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
for (let idx = 0; idx < listPendingStepIds.Items.length; idx++) {
|
|
323
|
+
|
|
324
|
+
if (currentAwaitingStepId && listPendingStepIds.Items[idx].awaitingStepId == currentAwaitingStepId) {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
// if any record found not set to complete then there are steps not yet finished
|
|
328
|
+
if (!listPendingStepIds.Items[idx].complete) {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return true;
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
// // mark currentAwaitingStepId as complete, this is done to protect against race condition in between checking all complete
|
|
337
|
+
// // and then removing the record, we need to let other requests know this record is complete and need to do this before
|
|
338
|
+
// // querying all remaining records, otherwise if have only two remaining requests they might both show as records remaining
|
|
339
|
+
// // (seeing each other) and not continue flow, then each deletes their record and no records remain to trigger next step.
|
|
340
|
+
// // can result in race condition where multiple requests see all records finished, code has to account for this, but should already do so for idempotence
|
|
341
|
+
// // add query that updates the currentAwaitingStepId to have attribute "complete" = true
|
|
342
|
+
// if (currentAwaitingStepId) {
|
|
343
|
+
// await dynamodbSharedLib.updateItem(
|
|
344
|
+
// _izContext,
|
|
345
|
+
// dynamodbSharedLib.tableName(tableName),
|
|
346
|
+
// {
|
|
347
|
+
// awaitingStepId: currentAwaitingStepId,
|
|
348
|
+
// pendingStepId: pendingStepId
|
|
349
|
+
// },
|
|
350
|
+
// {
|
|
351
|
+
// complete: true
|
|
352
|
+
// },
|
|
353
|
+
// )
|
|
354
|
+
// }
|
|
355
|
+
// let listPendingStepIds = await dynamodbSharedLib.query(
|
|
356
|
+
// _izContext,
|
|
357
|
+
// dynamodbSharedLib.tableName(tableName),
|
|
358
|
+
// {
|
|
359
|
+
// pendingStepId: pendingStepId
|
|
360
|
+
// },
|
|
361
|
+
// {
|
|
362
|
+
// indexName: dynamodbSharedLib.tableName(tableName + 'Index'),
|
|
363
|
+
// limit: 50 // arbritrary limit so not pull too many results, need >2 because some others might be marked as "complete" = true
|
|
364
|
+
// }
|
|
365
|
+
// );
|
|
366
|
+
// for (let idx = 0; idx < listPendingStepIds.Items.length; idx++) {
|
|
367
|
+
|
|
368
|
+
// if (currentAwaitingStepId && listPendingStepIds.Items[idx].awaitingStepId == currentAwaitingStepId) {
|
|
369
|
+
// continue;
|
|
370
|
+
// }
|
|
371
|
+
// // if any record found not set to complete then there are steps not yet finished
|
|
372
|
+
// if (!listPendingStepIds.Items[idx].complete) {
|
|
373
|
+
// return false;
|
|
374
|
+
// }
|
|
375
|
+
// }
|
|
376
|
+
|
|
377
|
+
// return true;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
module.exports.clearAllAwaitingSteps = async (
|
|
381
|
+
_izContext,
|
|
382
|
+
pendingStepId,
|
|
383
|
+
tableName = 'AwaitingMultipleSteps',
|
|
384
|
+
byPendingTableName = "AwaitingMultipleStepByPending"
|
|
385
|
+
) => {
|
|
386
|
+
_izContext.logger.debug("Lib:clearAllAwaitingSteps", {
|
|
387
|
+
pendingStepId: pendingStepId,
|
|
388
|
+
tableName: tableName,
|
|
389
|
+
byPendingTableName: byPendingTableName
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
tableName = await dynamodbSharedLib.tableName(_izContext, tableName)
|
|
393
|
+
|
|
394
|
+
// ----- query items from GSI table
|
|
395
|
+
let listPendingStepIds = await dynamodbSharedLib.query(
|
|
396
|
+
_izContext,
|
|
397
|
+
await dynamodbSharedLib.tableName(_izContext, byPendingTableName),
|
|
398
|
+
{
|
|
399
|
+
pendingStepId: pendingStepId
|
|
400
|
+
},
|
|
401
|
+
);
|
|
402
|
+
_izContext.logger.debug('listPendingStepIds', listPendingStepIds);
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
let promiseArray = []
|
|
406
|
+
|
|
407
|
+
for (let idx = 0; idx < listPendingStepIds.Items.length; idx++) {
|
|
408
|
+
|
|
409
|
+
let keyValues = {
|
|
410
|
+
awaitingStepId: listPendingStepIds.Items[idx].awaitingStepId,
|
|
411
|
+
pendingStepId: listPendingStepIds.Items[idx].pendingStepId
|
|
412
|
+
}
|
|
413
|
+
_izContext.logger.debug('deleting ... ', keyValues);
|
|
414
|
+
|
|
415
|
+
_izContext.logger.debug(`delete item in dynamodb AwaitingMultipleSteps ==> awaitingStepId:${keyValues.awaitingStepId}`)
|
|
416
|
+
promiseArray.push(
|
|
417
|
+
dynamodbSharedLib.deleteItem(
|
|
418
|
+
_izContext,
|
|
419
|
+
tableName,
|
|
420
|
+
keyValues
|
|
421
|
+
));
|
|
422
|
+
_izContext.logger.debug(`delete item in dynamodb AwaitingMultipleStepByPending ==> awaitingStepId:${keyValues.awaitingStepId}`)
|
|
423
|
+
promiseArray.push(
|
|
424
|
+
dynamodbSharedLib.deleteItem(
|
|
425
|
+
_izContext,
|
|
426
|
+
await dynamodbSharedLib.tableName(_izContext, byPendingTableName),
|
|
427
|
+
keyValues
|
|
428
|
+
));
|
|
429
|
+
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
await Promise.all(promiseArray);
|
|
433
|
+
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
module.exports.removeAwaitingStep = async (
|
|
439
|
+
_izContext,
|
|
440
|
+
awaitingStepId,
|
|
441
|
+
pendingStepId,
|
|
442
|
+
tableName = "AwaitingStep"
|
|
443
|
+
) => {
|
|
444
|
+
|
|
445
|
+
await dynamodbSharedLib.deleteItem(
|
|
446
|
+
_izContext,
|
|
447
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
448
|
+
{
|
|
449
|
+
awaitingStepId: awaitingStepId,
|
|
450
|
+
pendingStepId: pendingStepId
|
|
451
|
+
}
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
module.exports.removeAwaitingMultipleStep = async (
|
|
456
|
+
_izContext,
|
|
457
|
+
awaitingStepId,
|
|
458
|
+
pendingStepId,
|
|
459
|
+
tableName = "AwaitingMultipleSteps",
|
|
460
|
+
byPendingTableName = "AwaitingMultipleStepByPending"
|
|
461
|
+
) => {
|
|
462
|
+
_izContext.logger.debug("Lib:removeAwaitingMultipleStep", {
|
|
463
|
+
awaitingStepId: awaitingStepId,
|
|
464
|
+
pendingStepId: pendingStepId,
|
|
465
|
+
tableName: tableName,
|
|
466
|
+
byPendingTableName: byPendingTableName
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
let promiseArray = []
|
|
470
|
+
|
|
471
|
+
let keyValues = {
|
|
472
|
+
awaitingStepId: awaitingStepId,
|
|
473
|
+
pendingStepId: pendingStepId
|
|
474
|
+
}
|
|
475
|
+
_izContext.logger.debug('deleting ... ', keyValues);
|
|
476
|
+
|
|
477
|
+
_izContext.logger.debug(`delete item in dynamodb AwaitingMultipleSteps ==> awaitingStepId:${keyValues.awaitingStepId}`)
|
|
478
|
+
promiseArray.push(
|
|
479
|
+
dynamodbSharedLib.deleteItem(
|
|
480
|
+
_izContext,
|
|
481
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
482
|
+
keyValues
|
|
483
|
+
));
|
|
484
|
+
|
|
485
|
+
_izContext.logger.debug(`delete item in dynamodb AwaitingMultipleStepByPending ==> awaitingStepId:${keyValues.awaitingStepId}`)
|
|
486
|
+
promiseArray.push(
|
|
487
|
+
dynamodbSharedLib.deleteItem(
|
|
488
|
+
_izContext,
|
|
489
|
+
await dynamodbSharedLib.tableName(_izContext, byPendingTableName),
|
|
490
|
+
keyValues
|
|
491
|
+
));
|
|
492
|
+
|
|
493
|
+
await Promise.all(promiseArray);
|
|
494
|
+
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// only works with AwaitingStep, does not work with AwaitingMultipleSteps, need to make new function that checks conditional pass? If pass delete from byPending table too
|
|
498
|
+
module.exports.removeAwaitingStepWithCheckUniqueRequestId = async (
|
|
499
|
+
_izContext,
|
|
500
|
+
awaitingStepId,
|
|
501
|
+
pendingStepId,
|
|
502
|
+
checkUniqueRequestId,
|
|
503
|
+
prefix = "",
|
|
504
|
+
tableName = "AwaitingStep"
|
|
505
|
+
) => {
|
|
506
|
+
|
|
507
|
+
// if logicalElements add queryElements.logicalElements
|
|
508
|
+
// set condition uniqueRequestId match with exists
|
|
509
|
+
const queryElementsCondition = {
|
|
510
|
+
additionalAttributes: {
|
|
511
|
+
checkUniqueRequestId: checkUniqueRequestId,
|
|
512
|
+
},
|
|
513
|
+
logicalElements: [
|
|
514
|
+
{
|
|
515
|
+
type: "logical",
|
|
516
|
+
comparison: "equals",
|
|
517
|
+
lhsAttribute: this.createFieldNameUniqueRequestId(prefix),
|
|
518
|
+
rhsReference: "checkUniqueRequestId"
|
|
519
|
+
},
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
await dynamodbSharedLib.deleteItem(
|
|
524
|
+
_izContext,
|
|
525
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
526
|
+
{
|
|
527
|
+
awaitingStepId: awaitingStepId,
|
|
528
|
+
pendingStepId: pendingStepId
|
|
529
|
+
},
|
|
530
|
+
queryElementsCondition,
|
|
531
|
+
{
|
|
532
|
+
errorOnConditionalExpNotPass: false
|
|
533
|
+
}
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
//====================================== end AwaitingStep
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Checks if record has uniqueRequestId set, if not set to this requests uniqueRequestId and continue to process
|
|
547
|
+
* if already set check if matches this request uniqueRequestId, if yes continue to process, if not then stop processing
|
|
548
|
+
* status: "process"|"stop"|"recordNotFound"
|
|
549
|
+
|
|
550
|
+
* if unable to set uniqueRequestId (because other thread updated it) throw NoRetryError
|
|
551
|
+
* conditional update existingRecord set uniqueRequestId = _izContext.uniqueRequestId
|
|
552
|
+
* conditional check uniqueRequestId still not exist in case another thread added
|
|
553
|
+
* if conditional not pass "continue" and try again
|
|
554
|
+
|
|
555
|
+
* @returns [string] [returnStatus, existingRecord]
|
|
556
|
+
*/
|
|
557
|
+
module.exports.checkUniqueRequestProcessing = async (
|
|
558
|
+
_izContext,
|
|
559
|
+
tableName,
|
|
560
|
+
primaryKey,
|
|
561
|
+
prefix = '',
|
|
562
|
+
overwriteUniqueRequestId = null,
|
|
563
|
+
uniqueRequestIdFieldName = "UniqueRequestId" // if set will check/add this fieldname with _izContext.uniqueRequestId value
|
|
564
|
+
) => {
|
|
565
|
+
try {
|
|
566
|
+
|
|
567
|
+
_izContext.logger.debug('current uniqueRequestId:', _izContext.uniqueRequestId)
|
|
568
|
+
|
|
569
|
+
let uniqueRequestId = _izContext.uniqueRequestId;
|
|
570
|
+
if (overwriteUniqueRequestId) {
|
|
571
|
+
uniqueRequestId = overwriteUniqueRequestId;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// add prefix
|
|
575
|
+
uniqueRequestIdFieldName = this.createFieldNameUniqueRequestId(
|
|
576
|
+
prefix,
|
|
577
|
+
uniqueRequestIdFieldName
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
//loop 3 times incase status changes, on 3rd iteration throw error (so checks 2 times)
|
|
581
|
+
for (let i = 1; i <= 3; i++) {
|
|
582
|
+
if (i == 3) {
|
|
583
|
+
throw new NoRetryError(`unable to set uniqueRequestId in table ${tableName}, record`, primaryKey);
|
|
584
|
+
}
|
|
585
|
+
//* get record from dynamo
|
|
586
|
+
let existingRecord = await dynamodbSharedLib.getItem(
|
|
587
|
+
_izContext,
|
|
588
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
589
|
+
primaryKey,
|
|
590
|
+
)
|
|
591
|
+
_izContext.logger.debug('existingRecord:', existingRecord);
|
|
592
|
+
|
|
593
|
+
let returnStatus = "process";
|
|
594
|
+
|
|
595
|
+
if (!existingRecord) {
|
|
596
|
+
// return ["recordNotFound", null]; // cannot return null, js cannot found object and throw error and dont know where it is?
|
|
597
|
+
return ["recordNotFound", {}];
|
|
598
|
+
|
|
599
|
+
} else if (!existingRecord[uniqueRequestIdFieldName]) {
|
|
600
|
+
// uniqueRequestId not yet exist
|
|
601
|
+
|
|
602
|
+
let updateAttributes = [
|
|
603
|
+
{
|
|
604
|
+
attributeName: uniqueRequestIdFieldName,
|
|
605
|
+
action: "set",
|
|
606
|
+
value: _izContext.uniqueRequestId,
|
|
607
|
+
},
|
|
608
|
+
]
|
|
609
|
+
//* conditional check uniqueRequestId still not exist in case another thread added
|
|
610
|
+
const queryElementsWhenUpdate = {
|
|
611
|
+
logicalElements: [
|
|
612
|
+
{
|
|
613
|
+
type: "function",
|
|
614
|
+
function: "attribute_not_exists",
|
|
615
|
+
attribute: uniqueRequestIdFieldName,
|
|
616
|
+
}
|
|
617
|
+
],
|
|
618
|
+
returnValues: 'ALL_NEW'
|
|
619
|
+
}
|
|
620
|
+
// // ----- main query ---------
|
|
621
|
+
let updateRecord = null;
|
|
622
|
+
try {
|
|
623
|
+
updateRecord = await dynamodbSharedLib.updateItem(
|
|
624
|
+
_izContext,
|
|
625
|
+
await dynamodbSharedLib.tableName(_izContext, tableName),
|
|
626
|
+
primaryKey,
|
|
627
|
+
updateAttributes,
|
|
628
|
+
queryElementsWhenUpdate,
|
|
629
|
+
{ complexAttributes: true }, // force to complex
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
} catch (err) { // catch error when put and handle errors.
|
|
633
|
+
_izContext.logger.debug('updateItem storedCache expired err', err);
|
|
634
|
+
if (err.name == 'ConditionalCheckFailedException') {
|
|
635
|
+
continue;
|
|
636
|
+
} else { // e.g. ProvisionedThroughputExceededException
|
|
637
|
+
// throw new Error('Unhandled Error when putItem', err) // TT, if throw will stop
|
|
638
|
+
throw (err) // TT, if throw will stop
|
|
639
|
+
}
|
|
640
|
+
} //end catch err
|
|
641
|
+
|
|
642
|
+
} else if (existingRecord[uniqueRequestIdFieldName] !== uniqueRequestId) {
|
|
643
|
+
|
|
644
|
+
// when another request/uniqueRequestId need to stop process
|
|
645
|
+
returnStatus = "stop";
|
|
646
|
+
}
|
|
647
|
+
// if existingRecord[uniqueRequestIdFieldName] == uniqueRequestId then return "process"
|
|
648
|
+
|
|
649
|
+
return [returnStatus, existingRecord];
|
|
650
|
+
|
|
651
|
+
} // end loop 2 times
|
|
652
|
+
//should never get here
|
|
653
|
+
throw new NoRetryError('unexpected logic flow in checkUniqueRequestProcessing');
|
|
654
|
+
|
|
655
|
+
} catch (err) {
|
|
656
|
+
_izContext.logger.error('ERROR checkUniqueRequestProcessing:', err)
|
|
657
|
+
throw (err)
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
// ----- Helper funtion, common use case in triggerFlow ---------
|
|
662
|
+
module.exports.checkTimeCacheComplete = async (
|
|
663
|
+
_izContext,
|
|
664
|
+
fullMainTableName,
|
|
665
|
+
keyValues,
|
|
666
|
+
timeCacheComplete,
|
|
667
|
+
prefix
|
|
668
|
+
) => {
|
|
669
|
+
let [returnValue, newTimeCacheComplete, uniqueRequestId] = await this.checkAndGetTimeCacheComplete(
|
|
670
|
+
_izContext,
|
|
671
|
+
fullMainTableName,
|
|
672
|
+
keyValues,
|
|
673
|
+
timeCacheComplete,
|
|
674
|
+
prefix
|
|
675
|
+
);
|
|
676
|
+
return [returnValue, uniqueRequestId];
|
|
677
|
+
}
|
|
678
|
+
module.exports.checkAndGetTimeCacheComplete = async (
|
|
679
|
+
_izContext,
|
|
680
|
+
fullMainTableName,
|
|
681
|
+
keyValues,
|
|
682
|
+
timeCacheComplete,
|
|
683
|
+
prefix
|
|
684
|
+
) => {
|
|
685
|
+
_izContext.logger.debug('event checkTimeCacheComplete', {
|
|
686
|
+
fullMainTableName: fullMainTableName,
|
|
687
|
+
keyValues: keyValues,
|
|
688
|
+
timeCacheComplete: timeCacheComplete,
|
|
689
|
+
prefix: prefix
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
let uniqueRequestIdFieldName = triggeredCacheSharedLib.createFieldNameUniqueRequestId(prefix);
|
|
693
|
+
let cacheCompleteFieldName = triggeredCacheSharedLib.createFieldNameCacheComplete(prefix);
|
|
694
|
+
let statusFieldName = triggeredCacheSharedLib.createFieldNameStatus(prefix);
|
|
695
|
+
|
|
696
|
+
let getTimeCacheComplete = await dynamodbSharedLib.getItem(
|
|
697
|
+
_izContext,
|
|
698
|
+
fullMainTableName,
|
|
699
|
+
keyValues
|
|
700
|
+
)
|
|
701
|
+
_izContext.logger.debug(`getTimeCacheComplete from ${fullMainTableName}: `, getTimeCacheComplete);
|
|
702
|
+
|
|
703
|
+
if (!getTimeCacheComplete) {
|
|
704
|
+
throw new NoRetryError(`cannot getTimeCacheComplete from ${fullMainTableName}`);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// check if exist and match with initail create not changing in flow.
|
|
708
|
+
if (!getTimeCacheComplete[uniqueRequestIdFieldName]
|
|
709
|
+
// || !getTimeCacheComplete[cacheCompleteFieldName]
|
|
710
|
+
|| (getTimeCacheComplete[cacheCompleteFieldName]
|
|
711
|
+
&& getTimeCacheComplete[cacheCompleteFieldName] !== timeCacheComplete
|
|
712
|
+
&& getTimeCacheComplete[statusFieldName] != "complete")
|
|
713
|
+
) {
|
|
714
|
+
return [false, getTimeCacheComplete[cacheCompleteFieldName]];
|
|
715
|
+
} else {
|
|
716
|
+
return [true, getTimeCacheComplete[cacheCompleteFieldName], getTimeCacheComplete[uniqueRequestIdFieldName]];
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
// ----- shared both stored cache and triggered cache, check uniqueRequestId changed ---------
|
|
724
|
+
module.exports.checkCacheUniqueRequestId = async (
|
|
725
|
+
_izContext,
|
|
726
|
+
fullMainTableName,
|
|
727
|
+
keyValues,
|
|
728
|
+
checkUniqueRequestId,
|
|
729
|
+
uniqueRequestIdCompleteFieldName
|
|
730
|
+
) => {
|
|
731
|
+
|
|
732
|
+
let cacheObject = await dynamodbSharedLib.getItem(
|
|
733
|
+
_izContext,
|
|
734
|
+
fullMainTableName,
|
|
735
|
+
keyValues
|
|
736
|
+
)
|
|
737
|
+
_izContext.logger.debug('cacheObject', cacheObject);
|
|
738
|
+
|
|
739
|
+
if (!cacheObject[uniqueRequestIdCompleteFieldName] || cacheObject[uniqueRequestIdCompleteFieldName] !== checkUniqueRequestId) {
|
|
740
|
+
return false
|
|
741
|
+
} else {
|
|
742
|
+
return true
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
// use shared findPendingStepIdsAwaitingStep
|
|
752
|
+
// module.exports.findPendingStepIdsAwaitingStepM = async (
|
|
753
|
+
// _izContext,
|
|
754
|
+
// awaitingStepId,
|
|
755
|
+
// tableName = "AwaitingMultipleSteps"
|
|
756
|
+
// ) => {
|
|
757
|
+
|
|
758
|
+
// let pendingStepIds = [];
|
|
759
|
+
|
|
760
|
+
// let listPendingStepIds = await dynamodbSharedLib.query(
|
|
761
|
+
// _izContext,
|
|
762
|
+
// dynamodbSharedLib.tableName(tableName),
|
|
763
|
+
// {
|
|
764
|
+
// awaitingStepId: awaitingStepId
|
|
765
|
+
// }
|
|
766
|
+
// );
|
|
767
|
+
|
|
768
|
+
// for (let idx = 0; idx < listPendingStepIds.Items.length; idx++) {
|
|
769
|
+
// pendingStepIds.push(listPendingStepIds.Items[idx].pendingStepId)
|
|
770
|
+
// }
|
|
771
|
+
|
|
772
|
+
// return pendingStepIds
|
|
773
|
+
// }
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
// use shared removeAwaitingStep
|
|
779
|
+
// module.exports.removeAwaitingStep = async (
|
|
780
|
+
// _izContext,
|
|
781
|
+
// awaitingStepId,
|
|
782
|
+
// pendingStepId,
|
|
783
|
+
// tableName = "AwaitingMultipleSteps"
|
|
784
|
+
// ) => {
|
|
785
|
+
|
|
786
|
+
// await dynamodbSharedLib.deleteItem(
|
|
787
|
+
// _izContext,
|
|
788
|
+
// dynamodbSharedLib.tableName(tableName),
|
|
789
|
+
// {
|
|
790
|
+
// awaitingStepId: awaitingStepId,
|
|
791
|
+
// pendingStepId: pendingStepId
|
|
792
|
+
// }
|
|
793
|
+
// );
|
|
794
|
+
// }
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
//====================================== end AwaitingMultipleSteps
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
//====================================== end Multiple Lambda Invocations (Logic pagination of handling results)
|
|
802
|
+
|
|
803
|
+
module.exports.validateStartKeyParam = (
|
|
804
|
+
_izContext,
|
|
805
|
+
startKey,
|
|
806
|
+
partitionKeyFieldName,
|
|
807
|
+
sortKeyFieldName = null
|
|
808
|
+
) => {
|
|
809
|
+
|
|
810
|
+
if (startKey && Object.keys(startKey).length != 0) {
|
|
811
|
+
if (
|
|
812
|
+
startKey.constructor !== Object ||
|
|
813
|
+
!startKey[partitionKeyFieldName]
|
|
814
|
+
) {
|
|
815
|
+
startKey = false; // we can type check for false to see if invalid
|
|
816
|
+
}
|
|
817
|
+
if (sortKeyFieldName !== null && sortKeyFieldName !== undefined && !startKey[sortKeyFieldName]) {
|
|
818
|
+
startKey = false;
|
|
819
|
+
}
|
|
820
|
+
} else {
|
|
821
|
+
startKey = null; // if empty set to null so lib functions process correctly (not want empty object)
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
return startKey;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
module.exports.validateMultipleInvocations = async (
|
|
829
|
+
_izContext,
|
|
830
|
+
messageProperty,
|
|
831
|
+
passOnStartKey = {},
|
|
832
|
+
numberInvocation,
|
|
833
|
+
queueName
|
|
834
|
+
) => {
|
|
835
|
+
_izContext.logger.debug("Lib:validateMultipleInvocations", {
|
|
836
|
+
messageProperty: messageProperty,
|
|
837
|
+
passOnStartKey: passOnStartKey,
|
|
838
|
+
numberInvocation: numberInvocation,
|
|
839
|
+
queueName: queueName
|
|
840
|
+
});
|
|
841
|
+
try {
|
|
842
|
+
const maxProcessInvocationCountImport = 20
|
|
843
|
+
if (numberInvocation >= maxProcessInvocationCountImport) {
|
|
844
|
+
_izContext.logger.error("numberInvocation exceeds maxProcessInvocationCountImport limit");
|
|
845
|
+
throw new NoRetryError("numberInvocation exceeds maxProcessInvocationCountImport limit");
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
if (passOnStartKey) {
|
|
849
|
+
messageProperty["startKey"] = passOnStartKey
|
|
850
|
+
};
|
|
851
|
+
messageProperty["numberInvocation"] = numberInvocation;
|
|
852
|
+
|
|
853
|
+
let messageReInvokeFunction = {
|
|
854
|
+
MessageBody: JSON.stringify(
|
|
855
|
+
messageProperty
|
|
856
|
+
),
|
|
857
|
+
QueueUrl: await sqsSharedLib.sqsQueueUrl(_izContext, queueName)
|
|
858
|
+
};
|
|
859
|
+
_izContext.logger.debug(`Send mesage to Dsq:${queueName} `, messageReInvokeFunction);
|
|
860
|
+
await sqs.sendMessage(_izContext, messageReInvokeFunction);
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
} catch (err) {
|
|
864
|
+
throw (err)
|
|
865
|
+
}
|
|
866
|
+
}
|