@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 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
- // Import the Asynchronous Flow shared library functions
19
- import * as asyncFlowSharedLib from './src/asyncFlowSharedLib.js';
20
- import * as awaitingStep from './src/awaitingStep.js';
21
- import * as awaitingMultipleSteps from './src/awaitingMultipleSteps.js';
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
- ...asyncFlowSharedLib,
26
- ...awaitingStep,
27
- ...awaitingMultipleSteps
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.31",
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 incase status changes, on 3rd iteration throw error (so checks 2 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 dont know where it is?
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 funtion, common use case in triggerFlow ---------
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 mesage to Dsq:${queueName} `,
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 { identifierUuid } from '@izara_project/izara-shared-core';
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[]>} The list of awaiting step IDs created.
207
+ * @returns {Promise<string>} The awaiting step ID created.
220
208
  */
221
- export async function createNewAwaitingMultipleSteps(
209
+ export async function createNewAwaitingMultipleStep(
222
210
  _izContext,
223
211
  pendingStepId,
224
- parendIds,
212
+ prefix = '',
225
213
  additionalAttributes = {}
226
214
  ) {
227
215
  _izContext.logger.debug(
228
- '[Lib:AsyncFlow:createNewAwaitingMultipleSteps] Input: ',
216
+ '[Lib:AsyncFlow:createNewAwaitingMultipleStep] Input: ',
229
217
  {
230
218
  pendingStepId,
231
- countAwaitingMultipleSteps,
232
219
  additionalAttributes
233
220
  }
234
221
  );
235
222
 
236
- const promiseArray = [];
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
- const attributesForPending = {
254
- ...attributesWhenCreate,
255
- additionalAttributes: additionalAttributes
256
- };
225
+ const attributesWhenCreate = {
226
+ awaitingStepId: parentFlowId,
227
+ pendingStepId: pendingStepId,
228
+ complete: false,
229
+ errorsFound: []
230
+ };
257
231
 
258
- promiseArray.push(
259
- dynamodbSharedLib.putItem(
260
- _izContext,
261
- dynamodbSharedLib.tableName(
262
- _izContext,
263
- 'AwaitingMultipleStepByPending'
264
- ),
265
- attributesForPending
266
- )
267
- );
232
+ await dynamodbSharedLib.putItem(
233
+ _izContext,
234
+ dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleSteps'),
235
+ attributesWhenCreate
236
+ );
268
237
 
269
- _izContext.logger.debug('putItem:AwaitingMultipleStepByPending', {
270
- awaitingStepId: attributesWhenCreate.awaitingStepId
271
- });
272
- }
238
+ const attributesForPending = {
239
+ ...attributesWhenCreate,
240
+ additionalAttributes: additionalAttributes
241
+ };
273
242
 
274
- await Promise.all(promiseArray);
243
+ await dynamodbSharedLib.putItem(
244
+ _izContext,
245
+ dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleStepByPending'),
246
+ attributesForPending
247
+ );
275
248
 
276
- return parendIds;
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
+ }