@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.
- package/package.json +1 -1
- package/src/asyncFlowSharedLib.js +49 -98
- package/src/awaitingMultipleSteps.js +218 -470
- package/src/awaitingStep.js +51 -191
package/src/awaitingStep.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
|
23
|
-
|
|
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
|
-
//======================================
|
|
33
|
-
// AwaitingStep
|
|
34
|
-
|
|
35
|
-
//
|
|
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 = {},
|
|
52
|
-
callingFlowConfig = {}
|
|
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
|
|
63
|
-
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
|
-
|
|
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
|
|
96
|
-
|
|
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
|
-
|
|
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
|
|
181
|
-
|
|
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 [
|
|
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
|
|
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
|
|
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
|
}
|