@izara_project/izara-core-library-asynchronous-flow 1.0.30 → 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.30",
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
@@ -199,73 +201,52 @@ export async function createAwaitingMultipleSteps(
199
201
  * @async
200
202
  * @param {IzContext} _izContext
201
203
  * @param {string} pendingStepId
202
- * @param {number} countAwaitingMultipleSteps
204
+ * @param {string[]} parendIds
203
205
  * @param {Object.<string, any>} [additionalAttributes={}] - Shared attributes stored for every step in AwaitingMultipleStepByPending.
204
206
  * The same object is applied to all steps (caller cannot know the generated UUIDs beforehand).
205
- * @returns {Promise<string[]>} The list of awaiting step IDs created.
207
+ * @returns {Promise<string>} The awaiting step ID created.
206
208
  */
207
- export async function createNewAwaitingMultipleSteps(
209
+ export async function createNewAwaitingMultipleStep(
208
210
  _izContext,
209
211
  pendingStepId,
210
- countAwaitingMultipleSteps,
211
212
  prefix = '',
212
213
  additionalAttributes = {}
213
214
  ) {
214
215
  _izContext.logger.debug(
215
- '[Lib:AsyncFlow:createNewAwaitingMultipleSteps] Input: ',
216
+ '[Lib:AsyncFlow:createNewAwaitingMultipleStep] Input: ',
216
217
  {
217
218
  pendingStepId,
218
- countAwaitingMultipleSteps,
219
219
  additionalAttributes
220
220
  }
221
221
  );
222
222
 
223
- const parendIds = Array.from(
224
- { length: countAwaitingMultipleSteps },
225
- () => (prefix ? `${prefix}_` : '') + identifierUuid.generate()
226
- );
227
-
228
- const promiseArray = [];
223
+ const parentFlowId = createParentFlowId(prefix);
229
224
 
230
- for (const parendId of parendIds) {
231
- const attributesWhenCreate = {
232
- awaitingStepId: parendId,
233
- pendingStepId: pendingStepId,
234
- complete: false,
235
- errorsFound: []
236
- };
237
- promiseArray.push(
238
- dynamodbSharedLib.putItem(
239
- _izContext,
240
- dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleSteps'),
241
- attributesWhenCreate
242
- )
243
- );
244
-
245
- const attributesForPending = {
246
- ...attributesWhenCreate,
247
- additionalAttributes: additionalAttributes
248
- };
225
+ const attributesWhenCreate = {
226
+ awaitingStepId: parentFlowId,
227
+ pendingStepId: pendingStepId,
228
+ complete: false,
229
+ errorsFound: []
230
+ };
249
231
 
250
- promiseArray.push(
251
- dynamodbSharedLib.putItem(
252
- _izContext,
253
- dynamodbSharedLib.tableName(
254
- _izContext,
255
- 'AwaitingMultipleStepByPending'
256
- ),
257
- attributesForPending
258
- )
259
- );
232
+ await dynamodbSharedLib.putItem(
233
+ _izContext,
234
+ dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleSteps'),
235
+ attributesWhenCreate
236
+ );
260
237
 
261
- _izContext.logger.debug('putItem:AwaitingMultipleStepByPending', {
262
- awaitingStepId: attributesWhenCreate.awaitingStepId
263
- });
264
- }
238
+ const attributesForPending = {
239
+ ...attributesWhenCreate,
240
+ additionalAttributes: additionalAttributes
241
+ };
265
242
 
266
- await Promise.all(promiseArray);
243
+ await dynamodbSharedLib.putItem(
244
+ _izContext,
245
+ dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleStepByPending'),
246
+ attributesForPending
247
+ );
267
248
 
268
- return parendIds;
249
+ return parentFlowId;
269
250
  }
270
251
 
271
252
  /**
@@ -653,3 +634,58 @@ export async function removeAwaitingMultipleStep(
653
634
  }
654
635
  await Promise.all(promiseArray);
655
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
+ }