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