@izara_project/izara-core-library-asynchronous-flow 1.0.31 → 1.0.32
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 +85 -8
- package/package.json +5 -5
- package/src/asyncFlowSharedLib.js +16 -4
- package/src/awaitingMultipleSteps.js +84 -56
package/index.js
CHANGED
|
@@ -15,14 +15,91 @@ You should have received a copy of the GNU Affero General Public License
|
|
|
15
15
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
import {
|
|
19
|
+
createFieldNameUniqueRequestId,
|
|
20
|
+
createConcatenatedAwaitingStepId,
|
|
21
|
+
createConcatenatedPendingStepId,
|
|
22
|
+
createAwaitingStepId,
|
|
23
|
+
createPendingStepId,
|
|
24
|
+
createParentFlowId,
|
|
25
|
+
explodePendingStepId,
|
|
26
|
+
createFieldNameCacheComplete,
|
|
27
|
+
createFieldNameStatus,
|
|
28
|
+
checkUniqueRequestProcessing,
|
|
29
|
+
checkTimeCacheComplete,
|
|
30
|
+
checkAndGetTimeCacheComplete,
|
|
31
|
+
checkCacheUniqueRequestId,
|
|
32
|
+
validateStartKeyParam,
|
|
33
|
+
validateMultipleInvocations
|
|
34
|
+
} from './src/asyncFlowSharedLib.js';
|
|
35
|
+
|
|
36
|
+
import {
|
|
37
|
+
createAwaitingStep,
|
|
38
|
+
findPendingStepIdsAwaitingStep,
|
|
39
|
+
findPendingStepsAwaitingStep,
|
|
40
|
+
findPendingStepAwaitingStep,
|
|
41
|
+
findPendingStepAwaitingStepWithCallingFlow,
|
|
42
|
+
removeAwaitingStep,
|
|
43
|
+
removeAwaitingStepWithCheckUniqueRequestId
|
|
44
|
+
} from './src/awaitingStep.js';
|
|
45
|
+
|
|
46
|
+
import {
|
|
47
|
+
createAwaitingMultipleStepsWithAdditionalAttributes,
|
|
48
|
+
initAwaitingStepsWithAttrs,
|
|
49
|
+
createAwaitingMultipleSteps,
|
|
50
|
+
createNewAwaitingMultipleStep,
|
|
51
|
+
findPendingStepIdsAwaitingMultipleSteps,
|
|
52
|
+
findPendingStepsAwaitingMultipleSteps,
|
|
53
|
+
findPendingStepAwaitingMultipleSteps,
|
|
54
|
+
findAwaitingMultipleStepByPending,
|
|
55
|
+
checkAllAwaitingStepsFinishedShared,
|
|
56
|
+
checkAllAwaitingStepsFinished,
|
|
57
|
+
checkAllAwaitingStepsFinishedWithReturnParams,
|
|
58
|
+
clearAllAwaitingSteps,
|
|
59
|
+
removeAwaitingMultipleStep,
|
|
60
|
+
createAwaitingMultipleStepsWithAdditionalAttributesAndPublish
|
|
61
|
+
} from './src/awaitingMultipleSteps.js';
|
|
22
62
|
|
|
23
|
-
// Combine all functions from the imported modules into a single export object.
|
|
24
63
|
export default {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
64
|
+
// asyncFlowSharedLib
|
|
65
|
+
createFieldNameUniqueRequestId,
|
|
66
|
+
createConcatenatedAwaitingStepId,
|
|
67
|
+
createConcatenatedPendingStepId,
|
|
68
|
+
createAwaitingStepId,
|
|
69
|
+
createPendingStepId,
|
|
70
|
+
createParentFlowId,
|
|
71
|
+
explodePendingStepId,
|
|
72
|
+
createFieldNameCacheComplete,
|
|
73
|
+
createFieldNameStatus,
|
|
74
|
+
checkUniqueRequestProcessing,
|
|
75
|
+
checkTimeCacheComplete,
|
|
76
|
+
checkAndGetTimeCacheComplete,
|
|
77
|
+
checkCacheUniqueRequestId,
|
|
78
|
+
validateStartKeyParam,
|
|
79
|
+
validateMultipleInvocations,
|
|
80
|
+
|
|
81
|
+
// awaitingStep
|
|
82
|
+
createAwaitingStep,
|
|
83
|
+
findPendingStepIdsAwaitingStep,
|
|
84
|
+
findPendingStepsAwaitingStep,
|
|
85
|
+
findPendingStepAwaitingStep,
|
|
86
|
+
findPendingStepAwaitingStepWithCallingFlow,
|
|
87
|
+
removeAwaitingStep,
|
|
88
|
+
removeAwaitingStepWithCheckUniqueRequestId,
|
|
89
|
+
|
|
90
|
+
// awaitingMultipleSteps
|
|
91
|
+
createAwaitingMultipleStepsWithAdditionalAttributes,
|
|
92
|
+
initAwaitingStepsWithAttrs,
|
|
93
|
+
createAwaitingMultipleSteps,
|
|
94
|
+
createNewAwaitingMultipleStep,
|
|
95
|
+
findPendingStepIdsAwaitingMultipleSteps,
|
|
96
|
+
findPendingStepsAwaitingMultipleSteps,
|
|
97
|
+
findPendingStepAwaitingMultipleSteps,
|
|
98
|
+
findAwaitingMultipleStepByPending,
|
|
99
|
+
checkAllAwaitingStepsFinishedShared,
|
|
100
|
+
checkAllAwaitingStepsFinished,
|
|
101
|
+
checkAllAwaitingStepsFinishedWithReturnParams,
|
|
102
|
+
clearAllAwaitingSteps,
|
|
103
|
+
removeAwaitingMultipleStep,
|
|
104
|
+
createAwaitingMultipleStepsWithAdditionalAttributesAndPublish
|
|
28
105
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"author": "Sven Mason <thebarbariansven@gmail.com>",
|
|
4
4
|
"license": "AGPL-3.0-or-later",
|
|
5
5
|
"homepage": "https://bitbucket.org/izara-core-libraries/izara-core-library-asynchronous-flow#readme",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.32",
|
|
7
7
|
"description": "Shared asynchronous flow logic",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "index.js",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"@izara_project/izara-core-library-dynamodb": "^1.0.19",
|
|
29
29
|
"@izara_project/izara-core-library-external-request": "^1.0.30",
|
|
30
30
|
"@izara_project/izara-core-library-logger": "^1.0.9",
|
|
31
|
-
"@izara_project/izara-core-library-sqs": "^1.0.7"
|
|
31
|
+
"@izara_project/izara-core-library-sqs": "^1.0.7",
|
|
32
|
+
"@izara_project/izara-core-library-sns": "^1.0.8",
|
|
33
|
+
"@izara_project/izara-shared-core": "^1.0.12"
|
|
32
34
|
},
|
|
33
35
|
"peerDependenciesMeta": {},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"@izara_project/izara-shared-core": "^1.0.12"
|
|
36
|
-
}
|
|
36
|
+
"dependencies": {}
|
|
37
37
|
}
|
|
@@ -26,6 +26,8 @@ import sqsSharedLib from '@izara_project/izara-core-library-sqs';
|
|
|
26
26
|
// External service interactions
|
|
27
27
|
import { sqs } from '@izara_project/izara-core-library-external-request';
|
|
28
28
|
|
|
29
|
+
import { identifierUuid } from '@izara_project/izara-shared-core';
|
|
30
|
+
|
|
29
31
|
/**
|
|
30
32
|
* Create a field name for storing the unique-request id, with optional prefix.
|
|
31
33
|
* @param {string} prefix
|
|
@@ -84,6 +86,16 @@ export function createPendingStepId(identifierId, prefix = '') {
|
|
|
84
86
|
return prefix + identifierId;
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Create parent Flow Id.
|
|
91
|
+
* @async
|
|
92
|
+
* @param {string} [prefix=''] - The prefix to prepend to the parent Ids.
|
|
93
|
+
* @returns {string} The parent Flow Id created.
|
|
94
|
+
*/
|
|
95
|
+
export function createParentFlowId(prefix = '') {
|
|
96
|
+
return (prefix ? `${prefix}_` : '') + identifierUuid.generate();
|
|
97
|
+
}
|
|
98
|
+
|
|
87
99
|
/**
|
|
88
100
|
* Remove the known prefix from a pendingStepId and validate it is not equal to the prefix.
|
|
89
101
|
* If prefix is empty, the original ID is returned.
|
|
@@ -183,7 +195,7 @@ export async function checkUniqueRequestProcessing(
|
|
|
183
195
|
uniqueRequestIdFieldName
|
|
184
196
|
);
|
|
185
197
|
|
|
186
|
-
//loop 3 times
|
|
198
|
+
//loop 3 times incas status changes, on 3rd iteration throw error (so checks 2 times)
|
|
187
199
|
for (let i = 1; i <= 3; i++) {
|
|
188
200
|
if (i == 3) {
|
|
189
201
|
throw new NoRetryError(
|
|
@@ -202,7 +214,7 @@ export async function checkUniqueRequestProcessing(
|
|
|
202
214
|
let returnStatus = 'process';
|
|
203
215
|
|
|
204
216
|
if (!existingRecord) {
|
|
205
|
-
// return ["recordNotFound", null]; // cannot return null, js cannot found object and throw error and
|
|
217
|
+
// return ["recordNotFound", null]; // cannot return null, js cannot found object and throw error and don't know where it is?
|
|
206
218
|
return ['recordNotFound', {}];
|
|
207
219
|
} else if (!existingRecord[uniqueRequestIdFieldName]) {
|
|
208
220
|
// uniqueRequestId not yet exist
|
|
@@ -267,7 +279,7 @@ export async function checkUniqueRequestProcessing(
|
|
|
267
279
|
}
|
|
268
280
|
}
|
|
269
281
|
|
|
270
|
-
// ----- Helper
|
|
282
|
+
// ----- Helper function, common use case in triggerFlow ---------
|
|
271
283
|
/**
|
|
272
284
|
* Convenience wrapper around checkAndGetTimeCacheComplete.
|
|
273
285
|
* Returns [isSameOrUnset, uniqueRequestIdWhenComplete].
|
|
@@ -497,7 +509,7 @@ export async function validateMultipleInvocations(
|
|
|
497
509
|
QueueUrl: await sqsSharedLib.sqsQueueUrl(_izContext, queueName)
|
|
498
510
|
};
|
|
499
511
|
_izContext.logger.debug(
|
|
500
|
-
`Send
|
|
512
|
+
`Send message to Dsq:${queueName} `,
|
|
501
513
|
messageReInvokeFunction
|
|
502
514
|
);
|
|
503
515
|
await sqs.sendMessage(_izContext, messageReInvokeFunction);
|
|
@@ -17,8 +17,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
17
17
|
|
|
18
18
|
import { NoRetryError } from '@izara_project/izara-core-library-core';
|
|
19
19
|
import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
20
|
+
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
21
|
+
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
20
22
|
|
|
21
|
-
import {
|
|
23
|
+
import { createParentFlowId } from './asyncFlowSharedLib.js';
|
|
22
24
|
|
|
23
25
|
//====================================== AwaitingMultipleSteps
|
|
24
26
|
// AwaitingMultipleSteps is when a flow is awaiting multiple external flows before it can continue
|
|
@@ -26,20 +28,6 @@ import { identifierUuid } from '@izara_project/izara-shared-core';
|
|
|
26
28
|
// One pendingStepId can have multiple awaitingStepIds it is awaiting
|
|
27
29
|
// logic can prepend any prefix to awaitingStepId if want to be share one table and differentiate different external step ids
|
|
28
30
|
|
|
29
|
-
/**
|
|
30
|
-
* Create multiple parent Ids.
|
|
31
|
-
* @async
|
|
32
|
-
* @param {number} count - The number of parent Ids to create.
|
|
33
|
-
* @param {string} [prefix=''] - The prefix to prepend to the parent Ids.
|
|
34
|
-
* @returns {Promise<string[]>} The list of parent Ids created.
|
|
35
|
-
*/
|
|
36
|
-
export function createParendIds(count, prefix = '') {
|
|
37
|
-
return Array.from(
|
|
38
|
-
{ length: count },
|
|
39
|
-
() => (prefix ? `${prefix}_` : '') + identifierUuid.generate()
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
31
|
/**
|
|
44
32
|
* Create multiple awaiting records with optional per-record additional attributes.
|
|
45
33
|
* Writes to both "AwaitingMultipleSteps" and "AwaitingMultipleStepByPending".
|
|
@@ -216,64 +204,49 @@ export async function createAwaitingMultipleSteps(
|
|
|
216
204
|
* @param {string[]} parendIds
|
|
217
205
|
* @param {Object.<string, any>} [additionalAttributes={}] - Shared attributes stored for every step in AwaitingMultipleStepByPending.
|
|
218
206
|
* The same object is applied to all steps (caller cannot know the generated UUIDs beforehand).
|
|
219
|
-
* @returns {Promise<string
|
|
207
|
+
* @returns {Promise<string>} The awaiting step ID created.
|
|
220
208
|
*/
|
|
221
|
-
export async function
|
|
209
|
+
export async function createNewAwaitingMultipleStep(
|
|
222
210
|
_izContext,
|
|
223
211
|
pendingStepId,
|
|
224
|
-
|
|
212
|
+
prefix = '',
|
|
225
213
|
additionalAttributes = {}
|
|
226
214
|
) {
|
|
227
215
|
_izContext.logger.debug(
|
|
228
|
-
'[Lib:AsyncFlow:
|
|
216
|
+
'[Lib:AsyncFlow:createNewAwaitingMultipleStep] Input: ',
|
|
229
217
|
{
|
|
230
218
|
pendingStepId,
|
|
231
|
-
countAwaitingMultipleSteps,
|
|
232
219
|
additionalAttributes
|
|
233
220
|
}
|
|
234
221
|
);
|
|
235
222
|
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
for (const parendId of parendIds) {
|
|
239
|
-
const attributesWhenCreate = {
|
|
240
|
-
awaitingStepId: parendId,
|
|
241
|
-
pendingStepId: pendingStepId,
|
|
242
|
-
complete: false,
|
|
243
|
-
errorsFound: []
|
|
244
|
-
};
|
|
245
|
-
promiseArray.push(
|
|
246
|
-
dynamodbSharedLib.putItem(
|
|
247
|
-
_izContext,
|
|
248
|
-
dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleSteps'),
|
|
249
|
-
attributesWhenCreate
|
|
250
|
-
)
|
|
251
|
-
);
|
|
223
|
+
const parentFlowId = createParentFlowId(prefix);
|
|
252
224
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
225
|
+
const attributesWhenCreate = {
|
|
226
|
+
awaitingStepId: parentFlowId,
|
|
227
|
+
pendingStepId: pendingStepId,
|
|
228
|
+
complete: false,
|
|
229
|
+
errorsFound: []
|
|
230
|
+
};
|
|
257
231
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
'AwaitingMultipleStepByPending'
|
|
264
|
-
),
|
|
265
|
-
attributesForPending
|
|
266
|
-
)
|
|
267
|
-
);
|
|
232
|
+
await dynamodbSharedLib.putItem(
|
|
233
|
+
_izContext,
|
|
234
|
+
dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleSteps'),
|
|
235
|
+
attributesWhenCreate
|
|
236
|
+
);
|
|
268
237
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
238
|
+
const attributesForPending = {
|
|
239
|
+
...attributesWhenCreate,
|
|
240
|
+
additionalAttributes: additionalAttributes
|
|
241
|
+
};
|
|
273
242
|
|
|
274
|
-
await
|
|
243
|
+
await dynamodbSharedLib.putItem(
|
|
244
|
+
_izContext,
|
|
245
|
+
dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleStepByPending'),
|
|
246
|
+
attributesForPending
|
|
247
|
+
);
|
|
275
248
|
|
|
276
|
-
return
|
|
249
|
+
return parentFlowId;
|
|
277
250
|
}
|
|
278
251
|
|
|
279
252
|
/**
|
|
@@ -661,3 +634,58 @@ export async function removeAwaitingMultipleStep(
|
|
|
661
634
|
}
|
|
662
635
|
await Promise.all(promiseArray);
|
|
663
636
|
}
|
|
637
|
+
|
|
638
|
+
export async function createAwaitingMultipleStepsWithAdditionalAttributesAndPublish(
|
|
639
|
+
_izContext,
|
|
640
|
+
messages,
|
|
641
|
+
flowType = {},
|
|
642
|
+
additionalAttributes = {},
|
|
643
|
+
pendingStepId
|
|
644
|
+
) {
|
|
645
|
+
if (!Array.isArray(messages)) {
|
|
646
|
+
throw new Error('messages must be an array');
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
const flowTag = flowType.flowTag;
|
|
650
|
+
const serviceTag = flowType.serviceTag;
|
|
651
|
+
|
|
652
|
+
if (flowTag === undefined || serviceTag === undefined) {
|
|
653
|
+
throw new Error('flowType must have both flowTag and serviceTag');
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
_izContext.logger.debug(
|
|
657
|
+
'Lib:createAwaitingMultipleStepsWithAdditionalAttributesAndPublish',
|
|
658
|
+
{ count: messages.length, pendingStepId, flowType }
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
const topicArn = snsSharedLib.snsTopicArn(
|
|
662
|
+
_izContext,
|
|
663
|
+
flowType.flowTag,
|
|
664
|
+
flowType.serviceTag ?? null
|
|
665
|
+
);
|
|
666
|
+
|
|
667
|
+
const messagesWithParentId = await Promise.all(
|
|
668
|
+
messages.map(async message => {
|
|
669
|
+
const parentFlowId = await createNewAwaitingMultipleStep(
|
|
670
|
+
_izContext,
|
|
671
|
+
pendingStepId,
|
|
672
|
+
`${flowTag}${serviceTag}`,
|
|
673
|
+
additionalAttributes
|
|
674
|
+
);
|
|
675
|
+
return {
|
|
676
|
+
...message,
|
|
677
|
+
parentFlowId
|
|
678
|
+
};
|
|
679
|
+
})
|
|
680
|
+
);
|
|
681
|
+
|
|
682
|
+
await Promise.all(
|
|
683
|
+
messagesWithParentId.map(message =>
|
|
684
|
+
sns.publishAsync(_izContext, {
|
|
685
|
+
TopicArn: topicArn,
|
|
686
|
+
Message: JSON.stringify(message),
|
|
687
|
+
MessageAttributes: {}
|
|
688
|
+
})
|
|
689
|
+
)
|
|
690
|
+
);
|
|
691
|
+
}
|