@izara_project/izara-core-library-asynchronous-flow 1.0.14 → 1.0.16
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 +4 -1
- package/package.json +1 -1
- package/src/AsyncFlowSharedLib.js +373 -29
package/index.js
CHANGED
|
@@ -33,7 +33,10 @@ module.exports = {
|
|
|
33
33
|
// Awaiting Multiple Steps
|
|
34
34
|
createAwaitingMultipleStepsWithAdditionalAttributes: asyncFlowSharedLib.createAwaitingMultipleStepsWithAdditionalAttributes,
|
|
35
35
|
createAwaitingMultipleSteps: asyncFlowSharedLib.createAwaitingMultipleSteps,
|
|
36
|
-
|
|
36
|
+
findPendingStepIdsAwaitingMultipleSteps: asyncFlowSharedLib.findPendingStepIdsAwaitingMultipleSteps,
|
|
37
|
+
findPendingStepsAwaitingMultipleSteps: asyncFlowSharedLib.findPendingStepIdsAwaitingMultipleSteps,
|
|
38
|
+
findPendingStepAwaitingMultipleSteps: asyncFlowSharedLib.findPendingStepIdsAwaitingMultipleSteps,
|
|
39
|
+
findAwaitingMultipleStepByPending: asyncFlowSharedLib.findAwaitingMultipleStepByPending,
|
|
37
40
|
// Awaiting Step
|
|
38
41
|
createAwaitingStep: asyncFlowSharedLib.createAwaitingStep,
|
|
39
42
|
findPendingStepIdsAwaitingStep: asyncFlowSharedLib.findPendingStepIdsAwaitingStep,
|
package/package.json
CHANGED
|
@@ -28,6 +28,13 @@ const sqsSharedLib = require('@izara_project/izara-core-library-sqs');
|
|
|
28
28
|
// External service interactions
|
|
29
29
|
const { sqs } = require('@izara_project/izara-core-library-external-request');
|
|
30
30
|
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create a field name for storing the unique-request id, with optional prefix.
|
|
34
|
+
* @param {string} prefix
|
|
35
|
+
* @param {string} [uniqueRequestIdFieldName='UniqueRequestId']
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
31
38
|
function createFieldNameUniqueRequestId(
|
|
32
39
|
prefix,
|
|
33
40
|
uniqueRequestIdFieldName = 'UniqueRequestId'
|
|
@@ -35,6 +42,13 @@ function createFieldNameUniqueRequestId(
|
|
|
35
42
|
return prefix + uniqueRequestIdFieldName;
|
|
36
43
|
}
|
|
37
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Create a concatenated awaitingStepId from composite parts.
|
|
47
|
+
* @param {string} partitionKey
|
|
48
|
+
* @param {string|number} sortId
|
|
49
|
+
* @param {string} [prefix=""]
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
38
52
|
function createConcatenatedAwaitingStepId(
|
|
39
53
|
partitionKey,
|
|
40
54
|
sortId,
|
|
@@ -43,6 +57,12 @@ function createConcatenatedAwaitingStepId(
|
|
|
43
57
|
return prefix + partitionKey + "_" + sortId
|
|
44
58
|
}
|
|
45
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Create a concatenated pendingStepId from parent/child ids.
|
|
62
|
+
* @param {string} parentId
|
|
63
|
+
* @param {string} childId
|
|
64
|
+
* @returns {string}
|
|
65
|
+
*/
|
|
46
66
|
function createConcatenatedPendingStepId(
|
|
47
67
|
parentId,
|
|
48
68
|
childId
|
|
@@ -50,6 +70,12 @@ function createConcatenatedPendingStepId(
|
|
|
50
70
|
return parentId + "_" + childId
|
|
51
71
|
}
|
|
52
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Create a simple awaitingStepId (prefix + partitionKey).
|
|
75
|
+
* @param {string} partitionKey
|
|
76
|
+
* @param {string} [prefix=""]
|
|
77
|
+
* @returns {string}
|
|
78
|
+
*/
|
|
53
79
|
function createAwaitingStepId(
|
|
54
80
|
partitionKey,
|
|
55
81
|
prefix = ""
|
|
@@ -57,6 +83,12 @@ function createAwaitingStepId(
|
|
|
57
83
|
return prefix + partitionKey
|
|
58
84
|
}
|
|
59
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Create a simple pendingStepId (prefix + identifierId).
|
|
88
|
+
* @param {string} identifierId
|
|
89
|
+
* @param {string} [prefix=""]
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
60
92
|
function createPendingStepId(
|
|
61
93
|
identifierId,
|
|
62
94
|
prefix = ""
|
|
@@ -64,6 +96,14 @@ function createPendingStepId(
|
|
|
64
96
|
return prefix + identifierId
|
|
65
97
|
}
|
|
66
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Remove the known prefix from a pendingStepId and validate it is not equal to the prefix.
|
|
101
|
+
* If prefix is empty, the original ID is returned.
|
|
102
|
+
* @param {string} pendingStepId
|
|
103
|
+
* @param {string} [prefix=""]
|
|
104
|
+
* @returns {string}
|
|
105
|
+
* @throws {NoRetryError} If the stripped value equals the prefix (invalid)
|
|
106
|
+
*/
|
|
67
107
|
function explodePendingStepId(
|
|
68
108
|
pendingStepId,
|
|
69
109
|
prefix = ""
|
|
@@ -84,20 +124,40 @@ function explodePendingStepId(
|
|
|
84
124
|
}
|
|
85
125
|
|
|
86
126
|
// copy from izara-core-library-trigger-cache
|
|
127
|
+
/**
|
|
128
|
+
* Build the field name that stores "cache complete" marker.
|
|
129
|
+
* @param {string} [prefix='cache']
|
|
130
|
+
* @returns {string}
|
|
131
|
+
*/
|
|
87
132
|
function createFieldNameCacheComplete(prefix = 'cache') {
|
|
88
133
|
return prefix + 'CacheComplete';
|
|
89
134
|
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Build the field name that stores a cache "status".
|
|
138
|
+
* @param {string} [prefix='cache']
|
|
139
|
+
* @returns {string}
|
|
140
|
+
*/
|
|
90
141
|
function createFieldNameStatus(prefix = 'cache') {
|
|
91
142
|
return prefix + 'Status';
|
|
92
143
|
}
|
|
93
144
|
|
|
145
|
+
|
|
94
146
|
//====================================== AwaitingMultipleSteps
|
|
95
147
|
// AwaitingMultipleSteps is when a flow is awaiting multiple external flows before it can continue
|
|
96
148
|
// One awaitingStepId can have multiple pendingStepIds that are awaiting it
|
|
97
149
|
// One pendingStepId can have multiple awaitingStepIds it is awaiting
|
|
98
150
|
// logic can prepend any prefix to awaitingStepId if want to be share one table and differentiate different external step ids
|
|
99
151
|
|
|
100
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Create multiple awaiting records with optional per-record additional attributes.
|
|
154
|
+
* Writes to both "AwaitingMultipleSteps" and "AwaitingMultipleStepByPending".
|
|
155
|
+
* @async
|
|
156
|
+
* @param {IzContext} _izContext
|
|
157
|
+
* @param {AwaitingMultiInputRecord[]} records
|
|
158
|
+
* @param {string} pendingStepId
|
|
159
|
+
* @returns {Promise<void>}
|
|
160
|
+
*/
|
|
101
161
|
async function createAwaitingMultipleStepsWithAdditionalAttributes(
|
|
102
162
|
_izContext,
|
|
103
163
|
records, // array of object including properties: awaitingStepId / (optional) additionalAttributes
|
|
@@ -142,6 +202,15 @@ async function createAwaitingMultipleStepsWithAdditionalAttributes(
|
|
|
142
202
|
|
|
143
203
|
}
|
|
144
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Create multiple awaiting records given an array of awaitingStepIds.
|
|
207
|
+
* Writes to both "AwaitingMultipleSteps" and "AwaitingMultipleStepByPending".
|
|
208
|
+
* @async
|
|
209
|
+
* @param {IzContext} _izContext
|
|
210
|
+
* @param {string[]} records - array of awaitingStepIds
|
|
211
|
+
* @param {string} pendingStepId
|
|
212
|
+
* @returns {Promise<void>}
|
|
213
|
+
*/
|
|
145
214
|
async function createAwaitingMultipleSteps(
|
|
146
215
|
_izContext,
|
|
147
216
|
records, // array of awaitingStepIds
|
|
@@ -188,11 +257,130 @@ async function createAwaitingMultipleSteps(
|
|
|
188
257
|
|
|
189
258
|
}
|
|
190
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Find all pendingStepIds that are waiting on a given awaitingStepId (multiple).
|
|
262
|
+
* @async
|
|
263
|
+
* @param {IzContext} _izContext
|
|
264
|
+
* @param {string} awaitingStepId
|
|
265
|
+
* @returns {Promise<string[]>}
|
|
266
|
+
*/
|
|
267
|
+
async function findPendingStepIdsAwaitingMultipleSteps(
|
|
268
|
+
_izContext,
|
|
269
|
+
awaitingStepId
|
|
270
|
+
) {
|
|
271
|
+
|
|
272
|
+
let pendingStepIds = [];
|
|
273
|
+
|
|
274
|
+
let listPendingStepIds = await dynamodbSharedLib.query(
|
|
275
|
+
_izContext,
|
|
276
|
+
await dynamodbSharedLib.tableName(_izContext, "AwaitingMultipleSteps"),
|
|
277
|
+
{
|
|
278
|
+
awaitingStepId: awaitingStepId
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
for (let idx = 0; idx < listPendingStepIds.Items.length; idx++) {
|
|
283
|
+
pendingStepIds.push(listPendingStepIds.Items[idx].pendingStepId)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return pendingStepIds
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Return the raw items waiting on a given awaitingStepId (multiple).
|
|
291
|
+
* @async
|
|
292
|
+
* @param {IzContext} _izContext
|
|
293
|
+
* @param {string} awaitingStepId
|
|
294
|
+
* @returns {Promise<AwaitingMultipleStepsItem[]>}
|
|
295
|
+
*/
|
|
296
|
+
async function findPendingStepsAwaitingMultipleSteps(
|
|
297
|
+
_izContext,
|
|
298
|
+
awaitingStepId
|
|
299
|
+
) {
|
|
300
|
+
|
|
301
|
+
let listPendingSteps = await dynamodbSharedLib.query(
|
|
302
|
+
_izContext,
|
|
303
|
+
await dynamodbSharedLib.tableName(_izContext, "AwaitingMultipleSteps"),
|
|
304
|
+
{
|
|
305
|
+
awaitingStepId: awaitingStepId
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
_izContext.logger.debug("Record of awaitingStepId", listPendingSteps);
|
|
309
|
+
return listPendingSteps.Items;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Fetch exactly one pending step for a given awaitingStepId (throws if not 1).
|
|
314
|
+
* @async
|
|
315
|
+
* @param {IzContext} _izContext
|
|
316
|
+
* @param {string} awaitingStepId
|
|
317
|
+
* @returns {Promise<AwaitingMultipleStepsItem>}
|
|
318
|
+
* @throws {NoRetryError} if there is not exactly one item
|
|
319
|
+
*/
|
|
320
|
+
async function findPendingStepAwaitingMultipleSteps(
|
|
321
|
+
_izContext,
|
|
322
|
+
awaitingStepId
|
|
323
|
+
) {
|
|
324
|
+
|
|
325
|
+
let listPendingSteps = await dynamodbSharedLib.query(
|
|
326
|
+
_izContext,
|
|
327
|
+
await dynamodbSharedLib.tableName(_izContext, "AwaitingMultipleSteps"),
|
|
328
|
+
{
|
|
329
|
+
awaitingStepId: awaitingStepId
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
_izContext.logger.debug("Record of awaitingStepId", listPendingSteps)
|
|
333
|
+
|
|
334
|
+
if (listPendingSteps.Items.length !== 1) {
|
|
335
|
+
throw new NoRetryError("listPendingSteps not equals 1")
|
|
336
|
+
};
|
|
337
|
+
return listPendingSteps.Items[0];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Use case:
|
|
341
|
+
// Use only after checkAllAwaitingStepsFinished
|
|
342
|
+
// Do NOT delete records in both tables (AwaitingMultipleSteps, AwaitingMultipleStepByPending) if AwaitingMultipleSteps is not yet finished
|
|
343
|
+
// Delete records from both tables only when checkAllAwaitingStepsFinished = true
|
|
344
|
+
// Example usage: flow validateCart lambda ProcessCartOrderFromTraversal
|
|
345
|
+
/**
|
|
346
|
+
* Given a pendingStepId, return all awaiting steps (by the ByPending table).
|
|
347
|
+
* Use only after confirming all awaiting steps are finished, and clean up both tables accordingly.
|
|
348
|
+
* @async
|
|
349
|
+
* @param {IzContext} _izContext
|
|
350
|
+
* @param {string} pendingStepId
|
|
351
|
+
* @returns {Promise<AwaitingMultipleStepByPendingItem[]>}
|
|
352
|
+
*/
|
|
353
|
+
async function findAwaitingMultipleStepByPending(
|
|
354
|
+
_izContext,
|
|
355
|
+
pendingStepId
|
|
356
|
+
) {
|
|
357
|
+
|
|
358
|
+
let listAwitingSteps = await dynamodbSharedLib.query(
|
|
359
|
+
_izContext,
|
|
360
|
+
await dynamodbSharedLib.tableName(_izContext, "AwaitingMultipleStepByPending"),
|
|
361
|
+
{
|
|
362
|
+
pendingStepId: pendingStepId
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
_izContext.logger.debug("Record of AwaitingMultipleStepByPending", listAwitingSteps);
|
|
366
|
+
return listAwitingSteps.Items;
|
|
367
|
+
}
|
|
368
|
+
|
|
191
369
|
//====================================== AwaitingStep //======================================
|
|
192
370
|
// AwaitingStep is when a flow is awaiting one external flow, and will continue it's flow once that one external flow is complete
|
|
193
371
|
// One awaitingStepId can have multiple pendingStepIds that are awaiting it
|
|
194
372
|
// logic can prepend any prefix to awaitingStepId if want to be share one table and differentiate different external step ids
|
|
195
373
|
|
|
374
|
+
/**
|
|
375
|
+
* Create a single AwaitingStep record, optionally attaching additional attributes and callingFlowConfig.
|
|
376
|
+
* @async
|
|
377
|
+
* @param {IzContext} _izContext
|
|
378
|
+
* @param {string} awaitingStepId
|
|
379
|
+
* @param {string} pendingStepId
|
|
380
|
+
* @param {Attrs} [additionalAttributes={}]
|
|
381
|
+
* @param {Attrs} [callingFlowConfig={}]
|
|
382
|
+
* @returns {Promise<void>}
|
|
383
|
+
*/
|
|
196
384
|
async function createAwaitingStep(
|
|
197
385
|
_izContext,
|
|
198
386
|
awaitingStepId,
|
|
@@ -228,7 +416,13 @@ async function createAwaitingStep(
|
|
|
228
416
|
);
|
|
229
417
|
}
|
|
230
418
|
|
|
231
|
-
|
|
419
|
+
/**
|
|
420
|
+
* Find all pendingStepIds that are waiting on a given awaitingStepId (single).
|
|
421
|
+
* @async
|
|
422
|
+
* @param {IzContext} _izContext
|
|
423
|
+
* @param {string} awaitingStepId
|
|
424
|
+
* @returns {Promise<string[]>}
|
|
425
|
+
*/
|
|
232
426
|
async function findPendingStepIdsAwaitingStep(
|
|
233
427
|
_izContext,
|
|
234
428
|
awaitingStepId
|
|
@@ -251,6 +445,13 @@ async function findPendingStepIdsAwaitingStep(
|
|
|
251
445
|
return pendingStepIds
|
|
252
446
|
}
|
|
253
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Return the raw items waiting on a given awaitingStepId (single).
|
|
450
|
+
* @async
|
|
451
|
+
* @param {IzContext} _izContext
|
|
452
|
+
* @param {string} awaitingStepId
|
|
453
|
+
* @returns {Promise<AwaitingStepItem[]>}
|
|
454
|
+
*/
|
|
254
455
|
async function findPendingStepsAwaitingStep(
|
|
255
456
|
_izContext,
|
|
256
457
|
awaitingStepId
|
|
@@ -267,6 +468,14 @@ async function findPendingStepsAwaitingStep(
|
|
|
267
468
|
return listPendingSteps.Items;
|
|
268
469
|
}
|
|
269
470
|
|
|
471
|
+
/**
|
|
472
|
+
* Fetch exactly one pending step for a given awaitingStepId (throws if not 1).
|
|
473
|
+
* @async
|
|
474
|
+
* @param {IzContext} _izContext
|
|
475
|
+
* @param {string} awaitingStepId
|
|
476
|
+
* @returns {Promise<AwaitingStepItem>}
|
|
477
|
+
* @throws {NoRetryError} if there is not exactly one item
|
|
478
|
+
*/
|
|
270
479
|
async function findPendingStepAwaitingStep(
|
|
271
480
|
_izContext,
|
|
272
481
|
awaitingStepId
|
|
@@ -287,7 +496,15 @@ async function findPendingStepAwaitingStep(
|
|
|
287
496
|
return listPendingSteps.Items[0];
|
|
288
497
|
}
|
|
289
498
|
|
|
290
|
-
// for get callingFlow save in
|
|
499
|
+
// for get callingFlow save in awaitingStep and remove property callingFlow in awaitingStep
|
|
500
|
+
/**
|
|
501
|
+
* Get one awaiting step by id and also extract (and remove) its callingFlowConfig (if present).
|
|
502
|
+
* Returns a tuple: [AwaitingStepItemWithoutCallingFlow, callingFlowConfig|null].
|
|
503
|
+
* @async
|
|
504
|
+
* @param {IzContext} _izContext
|
|
505
|
+
* @param {string} awaitingStepId
|
|
506
|
+
* @returns {Promise<[AwaitingStepItem, Attrs|null]>}
|
|
507
|
+
*/
|
|
291
508
|
async function findPendingStepAwaitingStepWithCallingFlow(
|
|
292
509
|
_izContext,
|
|
293
510
|
awaitingStepId,
|
|
@@ -300,7 +517,7 @@ async function findPendingStepAwaitingStepWithCallingFlow(
|
|
|
300
517
|
);
|
|
301
518
|
|
|
302
519
|
// callingFlowConfig.
|
|
303
|
-
// cleaning object awaitingStep not have
|
|
520
|
+
// cleaning object awaitingStep not have callingFlowConfig after return.
|
|
304
521
|
if (awaitingStep.hasOwnProperty("callingFlowConfig")) {
|
|
305
522
|
callingFlowConfig = awaitingStep.callingFlowConfig
|
|
306
523
|
delete awaitingStep.callingFlowConfig
|
|
@@ -310,29 +527,51 @@ async function findPendingStepAwaitingStepWithCallingFlow(
|
|
|
310
527
|
return [awaitingStep, callingFlowConfig]
|
|
311
528
|
}
|
|
312
529
|
|
|
530
|
+
/**
|
|
531
|
+
* Mark current awaiting step as complete (in *_ByPending), then check if all awaiting steps are done.
|
|
532
|
+
* Returns true if all are finished; false otherwise.
|
|
533
|
+
* @async
|
|
534
|
+
* @param {IzContext} _izContext
|
|
535
|
+
* @param {string} pendingStepId
|
|
536
|
+
* @param {string|null} [currentAwaitingStepId=null]
|
|
537
|
+
* @param {any[]} [errorsFound=[]]
|
|
538
|
+
* @param {Attrs} [additionalAttributes={}]
|
|
539
|
+
* @returns {Promise<boolean>}
|
|
540
|
+
*/
|
|
313
541
|
async function checkAllAwaitingStepsFinished(
|
|
314
542
|
_izContext,
|
|
315
543
|
pendingStepId,
|
|
316
544
|
currentAwaitingStepId = null,
|
|
317
|
-
errorsFound = []
|
|
545
|
+
errorsFound = [],
|
|
546
|
+
additionalAttributes = {}
|
|
318
547
|
) {
|
|
319
548
|
|
|
320
549
|
let remaining = await checkAllAwaitingStepsFinishedWithError(
|
|
321
550
|
_izContext,
|
|
322
551
|
pendingStepId,
|
|
323
552
|
currentAwaitingStepId,
|
|
324
|
-
errorsFound
|
|
553
|
+
errorsFound,
|
|
554
|
+
additionalAttributes
|
|
325
555
|
);
|
|
326
556
|
return remaining;
|
|
327
557
|
}
|
|
328
558
|
|
|
329
|
-
|
|
330
|
-
|
|
559
|
+
/**
|
|
560
|
+
* Same as checkAllAwaitingStepsFinished but writes errors/additionalAttributes to the *_ByPending row.
|
|
561
|
+
* @async
|
|
562
|
+
* @param {IzContext} _izContext
|
|
563
|
+
* @param {string} pendingStepId
|
|
564
|
+
* @param {string|null} [currentAwaitingStepId=null]
|
|
565
|
+
* @param {any[]} [errorsFound=[]]
|
|
566
|
+
* @param {Attrs} [additionalAttributes={}]
|
|
567
|
+
* @returns {Promise<boolean>}
|
|
568
|
+
*/
|
|
331
569
|
async function checkAllAwaitingStepsFinishedWithError(
|
|
332
570
|
_izContext,
|
|
333
571
|
pendingStepId,
|
|
334
572
|
currentAwaitingStepId = null,
|
|
335
|
-
errorsFound = []
|
|
573
|
+
errorsFound = [],
|
|
574
|
+
additionalAttributes = {}
|
|
336
575
|
) {
|
|
337
576
|
_izContext.logger.debug("Lib:checkAllAwaitingStepsFinishedWithError", {
|
|
338
577
|
pendingStepId: pendingStepId,
|
|
@@ -350,7 +589,8 @@ async function checkAllAwaitingStepsFinishedWithError(
|
|
|
350
589
|
},
|
|
351
590
|
{
|
|
352
591
|
complete: true,
|
|
353
|
-
errorsFound: errorsFound
|
|
592
|
+
errorsFound: errorsFound,
|
|
593
|
+
...additionalAttributes
|
|
354
594
|
},
|
|
355
595
|
);
|
|
356
596
|
|
|
@@ -362,12 +602,12 @@ async function checkAllAwaitingStepsFinishedWithError(
|
|
|
362
602
|
pendingStepId: pendingStepId
|
|
363
603
|
},
|
|
364
604
|
{
|
|
365
|
-
limit: 50 //
|
|
605
|
+
limit: 50 // arbitrary limit so not pull too many results, need >2 because some others might be marked as "complete" = true
|
|
366
606
|
}
|
|
367
607
|
);
|
|
368
608
|
for (let idx = 0; idx < listPendingStepIds.Items.length; idx++) {
|
|
369
609
|
|
|
370
|
-
// if have error found return
|
|
610
|
+
// if have error found return errorsFound
|
|
371
611
|
// wrap function
|
|
372
612
|
|
|
373
613
|
if (currentAwaitingStepId && listPendingStepIds.Items[idx].awaitingStepId == currentAwaitingStepId) {
|
|
@@ -409,7 +649,7 @@ async function checkAllAwaitingStepsFinishedWithError(
|
|
|
409
649
|
// },
|
|
410
650
|
// {
|
|
411
651
|
// indexName: dynamodbSharedLib.tableName(tableName + 'Index'),
|
|
412
|
-
// limit: 50 //
|
|
652
|
+
// limit: 50 // arbitrary limit so not pull too many results, need >2 because some others might be marked as "complete" = true
|
|
413
653
|
// }
|
|
414
654
|
// );
|
|
415
655
|
// for (let idx = 0; idx < listPendingStepIds.Items.length; idx++) {
|
|
@@ -426,8 +666,13 @@ async function checkAllAwaitingStepsFinishedWithError(
|
|
|
426
666
|
// return true;
|
|
427
667
|
}
|
|
428
668
|
|
|
429
|
-
|
|
430
|
-
|
|
669
|
+
/**
|
|
670
|
+
* Remove all awaiting records for a given pendingStepId from both tables.
|
|
671
|
+
* @async
|
|
672
|
+
* @param {IzContext} _izContext
|
|
673
|
+
* @param {string} pendingStepId
|
|
674
|
+
* @returns {Promise<boolean>} true if delete flow processed
|
|
675
|
+
*/
|
|
431
676
|
async function clearAllAwaitingSteps(
|
|
432
677
|
_izContext,
|
|
433
678
|
pendingStepId
|
|
@@ -476,7 +721,14 @@ async function clearAllAwaitingSteps(
|
|
|
476
721
|
return true;
|
|
477
722
|
}
|
|
478
723
|
|
|
479
|
-
|
|
724
|
+
/**
|
|
725
|
+
* Remove a single AwaitingStep record (single dependency table).
|
|
726
|
+
* @async
|
|
727
|
+
* @param {IzContext} _izContext
|
|
728
|
+
* @param {string} awaitingStepId
|
|
729
|
+
* @param {string} pendingStepId
|
|
730
|
+
* @returns {Promise<void>}
|
|
731
|
+
*/
|
|
480
732
|
async function removeAwaitingStep(
|
|
481
733
|
_izContext,
|
|
482
734
|
awaitingStepId,
|
|
@@ -493,6 +745,16 @@ async function removeAwaitingStep(
|
|
|
493
745
|
);
|
|
494
746
|
}
|
|
495
747
|
|
|
748
|
+
/**
|
|
749
|
+
* Remove items for AwaitingMultipleSteps and (conditionally) AwaitingMultipleStepByPending.
|
|
750
|
+
* If errorsFound is empty, delete from ByPending table as well.
|
|
751
|
+
* @async
|
|
752
|
+
* @param {IzContext} _izContext
|
|
753
|
+
* @param {string} awaitingStepId
|
|
754
|
+
* @param {string} pendingStepId
|
|
755
|
+
* @param {any[]} [errorsFound=[]]
|
|
756
|
+
* @returns {Promise<void>}
|
|
757
|
+
*/
|
|
496
758
|
async function removeAwaitingMultipleStep(
|
|
497
759
|
_izContext,
|
|
498
760
|
awaitingStepId,
|
|
@@ -543,6 +805,17 @@ async function removeAwaitingMultipleStep(
|
|
|
543
805
|
}
|
|
544
806
|
|
|
545
807
|
// 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
|
|
808
|
+
/**
|
|
809
|
+
* Remove an AwaitingStep item only if its stored UniqueRequestId matches `checkUniqueRequestId`.
|
|
810
|
+
* Uses a conditional expression; will not error if the condition fails.
|
|
811
|
+
* @async
|
|
812
|
+
* @param {IzContext} _izContext
|
|
813
|
+
* @param {string} awaitingStepId
|
|
814
|
+
* @param {string} pendingStepId
|
|
815
|
+
* @param {string} checkUniqueRequestId
|
|
816
|
+
* @param {string} [prefix=""] - Optional prefix for UniqueRequestId field name
|
|
817
|
+
* @returns {Promise<void>}
|
|
818
|
+
*/
|
|
546
819
|
async function removeAwaitingStepWithCheckUniqueRequestId(
|
|
547
820
|
_izContext,
|
|
548
821
|
awaitingStepId,
|
|
@@ -581,14 +854,8 @@ async function removeAwaitingStepWithCheckUniqueRequestId(
|
|
|
581
854
|
);
|
|
582
855
|
}
|
|
583
856
|
|
|
584
|
-
|
|
585
|
-
|
|
586
857
|
//====================================== end AwaitingStep
|
|
587
858
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
859
|
/**
|
|
593
860
|
* Checks if record has uniqueRequestId set, if not set to this requests uniqueRequestId and continue to process
|
|
594
861
|
* if already set check if matches this request uniqueRequestId, if yes continue to process, if not then stop processing
|
|
@@ -601,6 +868,27 @@ async function removeAwaitingStepWithCheckUniqueRequestId(
|
|
|
601
868
|
|
|
602
869
|
* @returns [string] [returnStatus, existingRecord]
|
|
603
870
|
*/
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Coordinate unique-request processing over a record:
|
|
875
|
+
* - If no record: returns ["recordNotFound", {}]
|
|
876
|
+
* - If record exists but no uniqueRequestId: tries to set it via conditional update
|
|
877
|
+
* - If record has a different uniqueRequestId: returns ["stop", existingRecord]
|
|
878
|
+
* - If record has the same uniqueRequestId: returns ["process", existingRecord]
|
|
879
|
+
*
|
|
880
|
+
* Will loop up to 2 attempts to avoid races; throws on 3rd iteration.
|
|
881
|
+
*
|
|
882
|
+
* @async
|
|
883
|
+
* @param {IzContext} _izContext
|
|
884
|
+
* @param {string} tableName - Logical table name known by dynamodbSharedLib.tableName
|
|
885
|
+
* @param {DynamoKey} primaryKey - Primary key for the target record
|
|
886
|
+
* @param {string} [prefix=''] - Optional field-name prefix
|
|
887
|
+
* @param {string|null} [overwriteUniqueRequestId=null] - If provided, use this as the "current" unique request id
|
|
888
|
+
* @param {string} [uniqueRequestIdFieldName="UniqueRequestId"] - Base field name before prefix
|
|
889
|
+
* @returns {Promise<[UniqueRequestStatus, Attrs]>}
|
|
890
|
+
* @throws {NoRetryError} If unable to set uniqueRequestId after 2 tries
|
|
891
|
+
*/
|
|
604
892
|
async function checkUniqueRequestProcessing(
|
|
605
893
|
_izContext,
|
|
606
894
|
tableName,
|
|
@@ -706,6 +994,17 @@ async function checkUniqueRequestProcessing(
|
|
|
706
994
|
};
|
|
707
995
|
|
|
708
996
|
// ----- Helper funtion, common use case in triggerFlow ---------
|
|
997
|
+
/**
|
|
998
|
+
* Convenience wrapper around checkAndGetTimeCacheComplete.
|
|
999
|
+
* Returns [isSameOrUnset, uniqueRequestIdWhenComplete].
|
|
1000
|
+
* @async
|
|
1001
|
+
* @param {IzContext} _izContext
|
|
1002
|
+
* @param {string} fullMainTableName - Fully resolved table name (not logical)
|
|
1003
|
+
* @param {DynamoKey} keyValues
|
|
1004
|
+
* @param {number|string} timeCacheComplete - Caller’s expected cache mark
|
|
1005
|
+
* @param {string} prefix - Field prefix used in cache fields
|
|
1006
|
+
* @returns {Promise<[boolean, string|undefined]>}
|
|
1007
|
+
*/
|
|
709
1008
|
async function checkTimeCacheComplete(
|
|
710
1009
|
_izContext,
|
|
711
1010
|
fullMainTableName,
|
|
@@ -722,6 +1021,20 @@ async function checkTimeCacheComplete(
|
|
|
722
1021
|
);
|
|
723
1022
|
return [returnValue, uniqueRequestId];
|
|
724
1023
|
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Read cache fields from a record and compare cacheComplete value to caller’s `timeCacheComplete`.
|
|
1027
|
+
* If stored differs (and is present), returns [false, storedValue].
|
|
1028
|
+
* Otherwise returns [true, storedValue, uniqueRequestId].
|
|
1029
|
+
* @async
|
|
1030
|
+
* @param {IzContext} _izContext
|
|
1031
|
+
* @param {string} fullMainTableName - Fully resolved table name (not logical)
|
|
1032
|
+
* @param {DynamoKey} keyValues
|
|
1033
|
+
* @param {number|string} timeCacheComplete
|
|
1034
|
+
* @param {string} prefix
|
|
1035
|
+
* @returns {Promise<[boolean, any, string|undefined]>}
|
|
1036
|
+
* @throws {NoRetryError} If record cannot be fetched
|
|
1037
|
+
*/
|
|
725
1038
|
async function checkAndGetTimeCacheComplete(
|
|
726
1039
|
_izContext,
|
|
727
1040
|
fullMainTableName,
|
|
@@ -774,6 +1087,16 @@ async function checkAndGetTimeCacheComplete(
|
|
|
774
1087
|
|
|
775
1088
|
|
|
776
1089
|
// ----- shared both stored cache and triggered cache, check uniqueRequestId changed ---------
|
|
1090
|
+
/**
|
|
1091
|
+
* Ensure the cache object’s "uniqueRequestIdCompleteFieldName" equals the given checkUniqueRequestId.
|
|
1092
|
+
* @async
|
|
1093
|
+
* @param {IzContext} _izContext
|
|
1094
|
+
* @param {string} fullMainTableName
|
|
1095
|
+
* @param {DynamoKey} keyValues
|
|
1096
|
+
* @param {string} checkUniqueRequestId
|
|
1097
|
+
* @param {string} uniqueRequestIdCompleteFieldName
|
|
1098
|
+
* @returns {Promise<boolean>}
|
|
1099
|
+
*/
|
|
777
1100
|
async function checkCacheUniqueRequestId(
|
|
778
1101
|
_izContext,
|
|
779
1102
|
fullMainTableName,
|
|
@@ -797,10 +1120,6 @@ async function checkCacheUniqueRequestId(
|
|
|
797
1120
|
}
|
|
798
1121
|
|
|
799
1122
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
1123
|
// use shared findPendingStepIdsAwaitingStep
|
|
805
1124
|
// module.exports.findPendingStepIdsAwaitingStepM = async (
|
|
806
1125
|
// _izContext,
|
|
@@ -826,8 +1145,6 @@ async function checkCacheUniqueRequestId(
|
|
|
826
1145
|
// }
|
|
827
1146
|
|
|
828
1147
|
|
|
829
|
-
|
|
830
|
-
|
|
831
1148
|
// use shared removeAwaitingStep
|
|
832
1149
|
// module.exports.removeAwaitingStep = async (
|
|
833
1150
|
// _izContext,
|
|
@@ -853,6 +1170,17 @@ async function checkCacheUniqueRequestId(
|
|
|
853
1170
|
|
|
854
1171
|
//====================================== end Multiple Lambda Invocations (Logic pagination of handling results)
|
|
855
1172
|
|
|
1173
|
+
/**
|
|
1174
|
+
* Validate and normalize a DynamoDB pagination startKey object.
|
|
1175
|
+
* Ensures partitionKeyFieldName/sortKeyFieldName are alphanumeric/underscore/hyphen.
|
|
1176
|
+
* If startKey is empty object, returns `null` for easier processing downstream.
|
|
1177
|
+
* @param {IzContext} _izContext
|
|
1178
|
+
* @param {Attrs|null|undefined} startKey
|
|
1179
|
+
* @param {string} partitionKeyFieldName
|
|
1180
|
+
* @param {string} sortKeyFieldName
|
|
1181
|
+
* @returns {Attrs|null}
|
|
1182
|
+
* @throws {NoRetryError} On invalid field names or malformed startKey
|
|
1183
|
+
*/
|
|
856
1184
|
function validateStartKeyParam(
|
|
857
1185
|
_izContext,
|
|
858
1186
|
startKey,
|
|
@@ -880,7 +1208,19 @@ function validateStartKeyParam(
|
|
|
880
1208
|
return startKey;
|
|
881
1209
|
}
|
|
882
1210
|
|
|
883
|
-
|
|
1211
|
+
/**
|
|
1212
|
+
* For paginated multi-invocation flows: validates the current invocation count,
|
|
1213
|
+
* attaches the (optional) next startKey to the message, increments the count,
|
|
1214
|
+
* and re-enqueues the message to the specified SQS queue.
|
|
1215
|
+
* @async
|
|
1216
|
+
* @param {IzContext} _izContext
|
|
1217
|
+
* @param {Attrs} messageProperty - The message body object to re-dispatch
|
|
1218
|
+
* @param {Attrs} [passOnStartKey={}] - Optional startKey to pass along
|
|
1219
|
+
* @param {number} numberInvocation - Current invocation count
|
|
1220
|
+
* @param {string} queueName - Logical queue name resolvable via sqsSharedLib.sqsQueueUrl
|
|
1221
|
+
* @returns {Promise<void>}
|
|
1222
|
+
* @throws {NoRetryError} If `numberInvocation` exceeds internal safety limit
|
|
1223
|
+
*/
|
|
884
1224
|
async function validateMultipleInvocations(
|
|
885
1225
|
_izContext,
|
|
886
1226
|
messageProperty,
|
|
@@ -939,6 +1279,10 @@ module.exports = {
|
|
|
939
1279
|
checkAllAwaitingStepsFinished,
|
|
940
1280
|
clearAllAwaitingSteps,
|
|
941
1281
|
removeAwaitingMultipleStep,
|
|
1282
|
+
findPendingStepIdsAwaitingMultipleSteps,
|
|
1283
|
+
findPendingStepsAwaitingMultipleSteps,
|
|
1284
|
+
findPendingStepAwaitingMultipleSteps,
|
|
1285
|
+
findAwaitingMultipleStepByPending,
|
|
942
1286
|
|
|
943
1287
|
// AwaitingStep functions
|
|
944
1288
|
createAwaitingStep,
|