@izara_project/izara-core-library-asynchronous-flow 1.0.35 → 1.0.37

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
@@ -8,98 +8,19 @@ License, or (at your option) any later version.
8
8
 
9
9
  This program is distributed in the hope that it will be useful,
10
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
12
  GNU Affero General Public License for more details.
13
13
 
14
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/>.
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
  */
17
17
 
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';
18
+ import * as asyncFlowSharedLib from './src/asyncFlowSharedLib.js';
19
+ import * as awaitingStep from './src/awaitingStep.js';
20
+ import * as awaitingMultipleSteps from './src/awaitingMultipleSteps.js';
62
21
 
63
22
  export default {
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
23
+ ...asyncFlowSharedLib,
24
+ ...awaitingStep,
25
+ ...awaitingMultipleSteps
105
26
  };
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.35",
6
+ "version": "1.0.37",
7
7
  "description": "Shared asynchronous flow logic",
8
8
  "type": "module",
9
9
  "main": "index.js",
@@ -105,22 +105,15 @@ export function createParentFlowId(prefix = '') {
105
105
  * @throws {NoRetryError} If the stripped value equals the prefix (invalid)
106
106
  */
107
107
  export function explodePendingStepId(pendingStepId, prefix = '') {
108
- if (!pendingStepId) {
109
- throw NoRetryError('pendingStepId is required');
110
- }
108
+ if (!pendingStepId) throw new NoRetryError('pendingStepId is required');
109
+ if (!prefix) return pendingStepId;
111
110
 
112
- if (prefix === '') {
113
- return pendingStepId;
114
- } else {
115
- let identifierId = pendingStepId.slice(prefix.length);
116
- // ** validate identifierId == prefix
117
- if (identifierId == prefix) {
118
- throw new NoRetryError('IdentifierId should not be like prefix.');
119
- }
111
+ const identifierId = pendingStepId.slice(prefix.length);
112
+ if (identifierId === prefix)
113
+ throw new NoRetryError('IdentifierId should not be like prefix.');
120
114
 
121
- Logger.debug('return explode:', identifierId);
122
- return identifierId;
123
- }
115
+ Logger.debug('return explode:', identifierId);
116
+ return identifierId;
124
117
  }
125
118
 
126
119
  // copy from izara-core-library-trigger-cache
@@ -195,7 +188,7 @@ export async function checkUniqueRequestProcessing(
195
188
  );
196
189
 
197
190
  if (!tableName || !primaryKey) {
198
- throw NoRetryError('tableName and primaryKey are required');
191
+ throw new NoRetryError('tableName and primaryKey are required');
199
192
  }
200
193
 
201
194
  try {
@@ -204,94 +197,60 @@ export async function checkUniqueRequestProcessing(
204
197
  _izContext.uniqueRequestId
205
198
  );
206
199
 
207
- let uniqueRequestId = _izContext.uniqueRequestId;
208
- if (overwriteUniqueRequestId) {
209
- uniqueRequestId = overwriteUniqueRequestId;
210
- }
211
-
212
- // add prefix
200
+ const uniqueRequestId =
201
+ overwriteUniqueRequestId || _izContext.uniqueRequestId;
213
202
  uniqueRequestIdFieldName = createFieldNameUniqueRequestId(
214
203
  prefix,
215
204
  uniqueRequestIdFieldName
216
205
  );
217
206
 
218
- //loop 3 times incas status changes, on 3rd iteration throw error (so checks 2 times)
219
- for (let i = 1; i <= 3; i++) {
220
- if (i == 3) {
221
- throw new NoRetryError(
222
- `unable to set uniqueRequestId in table ${tableName}, record`,
223
- primaryKey
224
- );
225
- }
226
- //* get record from dynamo
227
- let existingRecord = await dynamodbSharedLib.getItem(
207
+ for (let i = 0; i < 2; i++) {
208
+ const existingRecord = await dynamodbSharedLib.getItem(
228
209
  _izContext,
229
210
  dynamodbSharedLib.tableName(_izContext, tableName),
230
211
  primaryKey
231
212
  );
232
- _izContext.logger.debug('existingRecord:', existingRecord);
233
213
 
234
- let returnStatus = 'process';
214
+ if (!existingRecord) return ['recordNotFound', {}];
235
215
 
236
- if (!existingRecord) {
237
- // return ["recordNotFound", null]; // cannot return null, js cannot found object and throw error and don't know where it is?
238
- return ['recordNotFound', {}];
239
- } else if (!existingRecord[uniqueRequestIdFieldName]) {
240
- // uniqueRequestId not yet exist
216
+ const currentReqId = existingRecord[uniqueRequestIdFieldName];
217
+ if (currentReqId === uniqueRequestId) return ['process', existingRecord];
218
+ if (currentReqId) return ['stop', existingRecord];
241
219
 
242
- let updateAttributes = [
243
- {
244
- attributeName: uniqueRequestIdFieldName,
245
- action: 'set',
246
- value: _izContext.uniqueRequestId
247
- }
248
- ];
249
- //* conditional check uniqueRequestId still not exist in case another thread added
250
- const queryElementsWhenUpdate = {
251
- logicalElements: [
220
+ try {
221
+ const updateRecord = await dynamodbSharedLib.updateItem(
222
+ _izContext,
223
+ dynamodbSharedLib.tableName(_izContext, tableName),
224
+ primaryKey,
225
+ [
252
226
  {
253
- type: 'function',
254
- function: 'attribute_not_exists',
255
- attribute: uniqueRequestIdFieldName
227
+ attributeName: uniqueRequestIdFieldName,
228
+ action: 'set',
229
+ value: _izContext.uniqueRequestId
256
230
  }
257
231
  ],
258
- returnValues: 'ALL_NEW'
259
- };
260
- // // ----- main query ---------
261
- let updateRecord = null;
262
- try {
263
- updateRecord = await dynamodbSharedLib.updateItem(
264
- _izContext,
265
- dynamodbSharedLib.tableName(_izContext, tableName),
266
- primaryKey,
267
- updateAttributes,
268
- queryElementsWhenUpdate,
269
- { complexAttributes: true } // force to complex
270
- );
271
-
272
- return [returnStatus, updateRecord];
273
- } catch (err) {
274
- // catch error when put and handle errors.
275
- _izContext.logger.debug('updateItem storedCache expired err', err);
276
- if (err.name == 'ConditionalCheckFailedException') {
277
- continue;
278
- } else {
279
- // e.g. ProvisionedThroughputExceededException
280
- // throw new Error('Unhandled Error when putItem', err) // TT, if throw will stop
281
- throw err; // TT, if throw will stop
282
- }
283
- } //end catch err
284
- } else if (existingRecord[uniqueRequestIdFieldName] !== uniqueRequestId) {
285
- // when another request/uniqueRequestId need to stop process
286
- return ['stop', existingRecord];
287
- } else if (existingRecord[uniqueRequestIdFieldName] == uniqueRequestId) {
288
- // if existingRecord[uniqueRequestIdFieldName] == uniqueRequestId then return "process
289
- return [returnStatus, existingRecord];
232
+ {
233
+ logicalElements: [
234
+ {
235
+ type: 'function',
236
+ function: 'attribute_not_exists',
237
+ attribute: uniqueRequestIdFieldName
238
+ }
239
+ ],
240
+ returnValues: 'ALL_NEW'
241
+ },
242
+ { complexAttributes: true }
243
+ );
244
+ return ['process', updateRecord];
245
+ } catch (err) {
246
+ if (err.name === 'ConditionalCheckFailedException') continue;
247
+ throw err;
290
248
  }
291
- } // end loop 2 times
292
- //should never get here
249
+ }
250
+
293
251
  throw new NoRetryError(
294
- 'unexpected logic flow in checkUniqueRequestProcessing'
252
+ `unable to set uniqueRequestId in table ${tableName}, record`,
253
+ primaryKey
295
254
  );
296
255
  } catch (err) {
297
256
  _izContext.logger.error('ERROR checkUniqueRequestProcessing:', err);
@@ -327,7 +286,7 @@ export async function checkTimeCacheComplete(
327
286
  });
328
287
 
329
288
  if (!fullMainTableName || !keyValues || !timeCacheComplete || !prefix) {
330
- throw NoRetryError(
289
+ throw new NoRetryError(
331
290
  'fullMainTableName, keyValues, timeCacheComplete and prefix are required'
332
291
  );
333
292
  }
@@ -437,21 +396,14 @@ export async function checkCacheUniqueRequestId(
437
396
  checkUniqueRequestId,
438
397
  uniqueRequestIdCompleteFieldName
439
398
  ) {
440
- let cacheObject = await dynamodbSharedLib.getItem(
399
+ const cacheObject = await dynamodbSharedLib.getItem(
441
400
  _izContext,
442
401
  fullMainTableName,
443
402
  keyValues
444
403
  );
445
404
  _izContext.logger.debug('cacheObject', cacheObject);
446
405
 
447
- if (
448
- !cacheObject[uniqueRequestIdCompleteFieldName] ||
449
- cacheObject[uniqueRequestIdCompleteFieldName] !== checkUniqueRequestId
450
- ) {
451
- return false;
452
- } else {
453
- return true;
454
- }
406
+ return cacheObject[uniqueRequestIdCompleteFieldName] === checkUniqueRequestId;
455
407
  }
456
408
 
457
409
  //====================================== end Multiple Lambda Invocations (Logic pagination of handling results)
@@ -492,17 +444,16 @@ export function validateStartKeyParam(
492
444
  );
493
445
  }
494
446
 
495
- if (startKey && Object.keys(startKey).length != 0) {
447
+ if (startKey && Object.keys(startKey).length !== 0) {
496
448
  if (!startKey[partitionKeyFieldName] || !startKey[sortKeyFieldName]) {
497
449
  throw new NoRetryError(
498
450
  'validateStartKeyParam: Invalid startKey, missing partitionKeyFieldName or sortKeyFieldName'
499
451
  );
500
452
  }
501
- } else {
502
- startKey = null; // if empty set to null so lib functions process correctly
453
+ return startKey;
503
454
  }
504
455
 
505
- return startKey;
456
+ return null;
506
457
  }
507
458
 
508
459
  /**