@izara_project/izara-core-library-asynchronous-flow 1.0.36 → 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.
@@ -1,5 +1,4 @@
1
- /*
2
- Copyright (C) 2021 Sven Mason <http://izara.io>
1
+ /* Copyright (C) 2021 Sven Mason <http://izara.io>
3
2
 
4
3
  This program is free software: you can redistribute it and/or modify
5
4
  it under the terms of the GNU Affero General Public License as
@@ -8,50 +7,54 @@ License, or (at your option) any later version.
8
7
 
9
8
  This program is distributed in the hope that it will be useful,
10
9
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
11
  GNU Affero General Public License for more details.
13
12
 
14
13
  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/>.
14
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
16
15
  */
17
16
 
18
17
  import { NoRetryError } from '@izara_project/izara-core-library-core';
19
18
  import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
19
+
20
20
  import { createFieldNameUniqueRequestId } from './asyncFlowSharedLib.js';
21
21
 
22
- async function queryAwaitingSteps(_izContext, awaitingStepId) {
23
- return dynamodbSharedLib.query(
22
+ async function _findSinglePendingStep(_izContext, awaitingStepId) {
23
+ _izContext.logger.debug('[Lib:AsyncFlow:findSinglePendingStep] Input', {
24
+ awaitingStepId
25
+ });
26
+
27
+ if (!awaitingStepId) {
28
+ throw new NoRetryError('awaitingStepId is required');
29
+ }
30
+
31
+ const { Items } = await dynamodbSharedLib.query(
24
32
  _izContext,
25
33
  dynamodbSharedLib.tableName(_izContext, 'AwaitingStep'),
26
- {
27
- awaitingStepId
28
- }
34
+ { awaitingStepId }
29
35
  );
36
+
37
+ if (Items.length !== 1) {
38
+ throw new NoRetryError('listPendingSteps not equals 1');
39
+ }
40
+
41
+ return Items[0];
30
42
  }
31
43
 
32
- //====================================== AwaitingStep //======================================
33
- // AwaitingStep is when a flow is awaiting one external flow, and will continue it's flow once that one external flow is complete
34
- // One awaitingStepId can have multiple pendingStepIds that are awaiting it
35
- // logic can prepend any prefix to awaitingStepId if want to be share one table and differentiate different external step ids
44
+ //======================================
45
+ // AwaitingStep
46
+ //======================================
47
+ // AwaitingStep flow awaiting one external flow, will continue its flow once one external flow completes.
48
+ // One awaitingStepId can have multiple pendingStepIds awaiting it.
36
49
 
37
- /**
38
- * Create a single AwaitingStep record, optionally attaching additional attributes and callingFlowConfig.
39
- * @async
40
- * @param {IzContext} _izContext
41
- * @param {string} awaitingStepId
42
- * @param {string} pendingStepId
43
- * @param {Attrs} [additionalAttributes={}]
44
- * @param {Attrs} [callingFlowConfig={}]
45
- * @returns {Promise<void>}
46
- */
47
50
  export async function createAwaitingStep(
48
51
  _izContext,
49
52
  awaitingStepId,
50
53
  pendingStepId,
51
- additionalAttributes = {}, // save in top level
52
- callingFlowConfig = {} // optional
54
+ additionalAttributes = {},
55
+ callingFlowConfig = {}
53
56
  ) {
54
- _izContext.logger.debug('[Lib:AsyncFlow:createAwaitingStep] Input: ', {
57
+ _izContext.logger.debug('[Lib:AsyncFlow:createAwaitingStep] Input', {
55
58
  awaitingStepId,
56
59
  pendingStepId,
57
60
  additionalAttributes,
@@ -59,19 +62,15 @@ export async function createAwaitingStep(
59
62
  });
60
63
 
61
64
  const attributesWhenCreate = {
62
- awaitingStepId: awaitingStepId,
63
- pendingStepId: pendingStepId,
65
+ awaitingStepId,
66
+ pendingStepId,
64
67
  timestamp: Date.now(),
65
- uniqueRequestId: _izContext.uniqueRequestId
68
+ uniqueRequestId: _izContext.uniqueRequestId,
69
+ ...additionalAttributes
66
70
  };
67
- // loop if not empty
68
- for (const additionalAttribute in additionalAttributes) {
69
- attributesWhenCreate[additionalAttribute] =
70
- additionalAttributes[additionalAttribute]; // each additionalAttributes
71
- }
72
71
 
73
72
  if (Object.keys(callingFlowConfig).length > 0) {
74
- Object.assign(attributesWhenCreate, { callingFlowConfig });
73
+ attributesWhenCreate.callingFlowConfig = callingFlowConfig;
75
74
  }
76
75
 
77
76
  await dynamodbSharedLib.putItem(
@@ -81,174 +80,49 @@ export async function createAwaitingStep(
81
80
  );
82
81
  }
83
82
 
84
- /**
85
- * Find all pendingStepIds that are waiting on a given awaitingStepId (single).
86
- * @async
87
- * @param {IzContext} _izContext
88
- * @param {string} awaitingStepId
89
- * @returns {Promise<string[]>}
90
- */
91
- export async function findPendingStepIdsAwaitingStep(
83
+ export async function findPendingStepIdAwaitingStep(
92
84
  _izContext,
93
85
  awaitingStepId
94
86
  ) {
95
- _izContext.logger.debug(
96
- '[Lib:AsyncFlow:findPendingStepIdsAwaitingStep] Input: ',
97
- {
98
- awaitingStepId
99
- }
100
- );
101
-
102
- if (!awaitingStepId) {
103
- throw new NoRetryError('awaitingStepId is required');
104
- }
105
-
106
- const listPendingStepIds = await queryAwaitingSteps(_izContext, awaitingStepId);
107
- return listPendingStepIds.Items.map(item => item.pendingStepId);
108
- }
109
-
110
- /**
111
- * Return the raw items waiting on a given awaitingStepId (single).
112
- * @async
113
- * @param {IzContext} _izContext
114
- * @param {string} awaitingStepId
115
- * @returns {Promise<AwaitingStepItem[]>}
116
- */
117
- export async function findPendingStepsAwaitingStep(_izContext, awaitingStepId) {
118
- _izContext.logger.debug(
119
- '[Lib:AsyncFlow:findPendingStepsAwaitingStep] Input: ',
120
- {
121
- awaitingStepId
122
- }
123
- );
124
-
125
- if (!awaitingStepId) {
126
- throw new NoRetryError('awaitingStepId is required');
127
- }
128
-
129
- const listPendingSteps = await queryAwaitingSteps(_izContext, awaitingStepId);
130
- _izContext.logger.debug('Record of awaitingStepId', listPendingSteps);
131
- return listPendingSteps.Items;
87
+ const item = await _findSinglePendingStep(_izContext, awaitingStepId);
88
+ return item.pendingStepId;
132
89
  }
133
90
 
134
- /**
135
- * Fetch exactly one pending step for a given awaitingStepId (throws if not 1).
136
- * @async
137
- * @param {IzContext} _izContext
138
- * @param {string} awaitingStepId
139
- * @returns {Promise<AwaitingStepItem>}
140
- * @throws {NoRetryError} if there is not exactly one item
141
- */
142
- export async function findPendingStepAwaitingStep(_izContext, awaitingStepId) {
143
- _izContext.logger.debug(
144
- '[Lib:AsyncFlow:findPendingStepAwaitingStep] Input: ',
145
- {
146
- awaitingStepId
147
- }
148
- );
149
-
150
- if (!awaitingStepId) {
151
- throw new NoRetryError('awaitingStepId is required');
152
- }
153
-
154
- const listPendingSteps = await queryAwaitingSteps(_izContext, awaitingStepId);
155
-
156
- _izContext.logger.debug(
157
- '[Lib:AsyncFlow:findPendingStepAwaitingStep] Found records: ',
158
- listPendingSteps
159
- );
160
-
161
- if (listPendingSteps.Items.length !== 1) {
162
- throw new NoRetryError('listPendingSteps not equals 1');
163
- }
164
- return listPendingSteps.Items[0];
91
+ export async function findPendingStep(_izContext, awaitingStepId) {
92
+ return _findSinglePendingStep(_izContext, awaitingStepId);
165
93
  }
166
94
 
167
- // for get callingFlow save in awaitingStep and remove property callingFlow in awaitingStep
168
- /**
169
- * Get one awaiting step by id and also extract (and remove) its callingFlowConfig (if present).
170
- * Returns a tuple: [AwaitingStepItemWithoutCallingFlow, callingFlowConfig|null].
171
- * @async
172
- * @param {IzContext} _izContext
173
- * @param {string} awaitingStepId
174
- * @returns {Promise<[AwaitingStepItem, Attrs|null]>}
175
- */
176
95
  export async function findPendingStepAwaitingStepWithCallingFlow(
177
96
  _izContext,
178
97
  awaitingStepId
179
98
  ) {
180
- _izContext.logger.debug(
181
- '[Lib:AsyncFlow:findPendingStepAwaitingStepWithCallingFlow] Input: ',
182
- {
183
- awaitingStepId
184
- }
185
- );
186
-
187
- if (!awaitingStepId) {
188
- throw new NoRetryError('awaitingStepId is required');
189
- }
190
-
191
- let callingFlowConfig = null;
192
- let awaitingStep = await findPendingStepAwaitingStep(
193
- _izContext,
194
- awaitingStepId
195
- );
196
-
197
- // callingFlowConfig.
198
- // cleaning object awaitingStep not have callingFlowConfig after return.
199
- if (awaitingStep.hasOwnProperty('callingFlowConfig')) {
200
- callingFlowConfig = awaitingStep.callingFlowConfig;
201
- delete awaitingStep.callingFlowConfig;
202
- _izContext.logger.debug('after delete awaitingStep', awaitingStep);
203
- }
99
+ const awaitingStep = await findPendingStep(_izContext, awaitingStepId);
100
+ const { callingFlowConfig = null, ...restAwaitingStep } = awaitingStep;
204
101
 
205
- return [awaitingStep, callingFlowConfig];
102
+ return [restAwaitingStep, callingFlowConfig];
206
103
  }
207
104
 
208
- /**
209
- * Remove a single AwaitingStep record (single dependency table).
210
- * @async
211
- * @param {IzContext} _izContext
212
- * @param {string} awaitingStepId
213
- * @param {string} pendingStepId
214
- * @returns {Promise<void>}
215
- */
216
105
  export async function removeAwaitingStep(
217
106
  _izContext,
218
107
  awaitingStepId,
219
108
  pendingStepId
220
109
  ) {
221
- _izContext.logger.debug('[Lib:AsyncFlow:removeAwaitingStep] Input: ', {
110
+ _izContext.logger.debug('[Lib:AsyncFlow:removeAwaitingStep] Input', {
222
111
  awaitingStepId,
223
112
  pendingStepId
224
113
  });
225
114
 
226
115
  if (!awaitingStepId || !pendingStepId) {
227
- throw new NoRetryError('awaitingStepId and pendingStepId are required');
116
+ throw new NoRetryError('awaitingStepId pendingStepId required');
228
117
  }
229
118
 
230
119
  await dynamodbSharedLib.deleteItem(
231
120
  _izContext,
232
121
  dynamodbSharedLib.tableName(_izContext, 'AwaitingStep'),
233
- {
234
- awaitingStepId: awaitingStepId,
235
- pendingStepId: pendingStepId
236
- }
122
+ { awaitingStepId, pendingStepId }
237
123
  );
238
124
  }
239
125
 
240
- // 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
241
- /**
242
- * Remove an AwaitingStep item only if its stored UniqueRequestId matches `checkUniqueRequestId`.
243
- * Uses a conditional expression; will not error if the condition fails.
244
- * @async
245
- * @param {IzContext} _izContext
246
- * @param {string} awaitingStepId
247
- * @param {string} pendingStepId
248
- * @param {string} checkUniqueRequestId
249
- * @param {string} [prefix=""] - Optional prefix for UniqueRequestId field name
250
- * @returns {Promise<void>}
251
- */
252
126
  export async function removeAwaitingStepWithCheckUniqueRequestId(
253
127
  _izContext,
254
128
  awaitingStepId,
@@ -257,27 +131,18 @@ export async function removeAwaitingStepWithCheckUniqueRequestId(
257
131
  prefix = ''
258
132
  ) {
259
133
  _izContext.logger.debug(
260
- '[Lib:AsyncFlow:removeAwaitingStepWithCheckUniqueRequestId] Input: ',
261
- {
262
- awaitingStepId,
263
- pendingStepId,
264
- checkUniqueRequestId,
265
- prefix
266
- }
134
+ '[Lib:AsyncFlow:removeAwaitingStepWithCheckUniqueRequestId] Input',
135
+ { awaitingStepId, pendingStepId, checkUniqueRequestId, prefix }
267
136
  );
268
137
 
269
138
  if (!awaitingStepId || !pendingStepId || !checkUniqueRequestId) {
270
139
  throw new NoRetryError(
271
- 'awaitingStepId, pendingStepId and checkUniqueRequestId are required'
140
+ 'awaitingStepId, pendingStepId checkUniqueRequestId required'
272
141
  );
273
142
  }
274
143
 
275
- // if logicalElements add queryElements.logicalElements
276
- // set condition uniqueRequestId match with exists
277
144
  const queryElementsCondition = {
278
- additionalAttributes: {
279
- checkUniqueRequestId: checkUniqueRequestId
280
- },
145
+ additionalAttributes: { checkUniqueRequestId },
281
146
  logicalElements: [
282
147
  {
283
148
  type: 'logical',
@@ -291,13 +156,8 @@ export async function removeAwaitingStepWithCheckUniqueRequestId(
291
156
  await dynamodbSharedLib.deleteItem(
292
157
  _izContext,
293
158
  dynamodbSharedLib.tableName(_izContext, 'AwaitingStep'),
294
- {
295
- awaitingStepId: awaitingStepId,
296
- pendingStepId: pendingStepId
297
- },
159
+ { awaitingStepId, pendingStepId },
298
160
  queryElementsCondition,
299
- {
300
- errorOnConditionalExpNotPass: false
301
- }
161
+ { errorOnConditionalExpNotPass: false }
302
162
  );
303
163
  }