@hotmeshio/hotmesh 0.0.52 → 0.0.54
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/README.md +22 -18
- package/build/index.d.ts +1 -2
- package/build/index.js +1 -3
- package/build/modules/enums.d.ts +8 -3
- package/build/modules/enums.js +16 -8
- package/build/modules/errors.d.ts +58 -20
- package/build/modules/errors.js +90 -33
- package/build/package.json +7 -2
- package/build/services/activities/activity.d.ts +8 -0
- package/build/services/activities/activity.js +63 -14
- package/build/services/activities/await.js +6 -6
- package/build/services/activities/cycle.d.ts +2 -2
- package/build/services/activities/cycle.js +5 -5
- package/build/services/activities/hook.js +9 -5
- package/build/services/activities/interrupt.d.ts +3 -3
- package/build/services/activities/interrupt.js +15 -6
- package/build/services/activities/signal.d.ts +2 -2
- package/build/services/activities/signal.js +4 -4
- package/build/services/activities/trigger.d.ts +5 -2
- package/build/services/activities/trigger.js +34 -4
- package/build/services/activities/worker.js +6 -6
- package/build/services/compiler/deployer.js +33 -5
- package/build/services/compiler/validator.d.ts +2 -0
- package/build/services/compiler/validator.js +5 -1
- package/build/services/durable/client.d.ts +7 -1
- package/build/services/durable/client.js +57 -38
- package/build/services/durable/exporter.d.ts +27 -81
- package/build/services/durable/exporter.js +153 -325
- package/build/services/durable/handle.d.ts +13 -8
- package/build/services/durable/handle.js +61 -48
- package/build/services/durable/index.d.ts +0 -2
- package/build/services/durable/index.js +0 -2
- package/build/services/durable/schemas/factory.d.ts +33 -0
- package/build/services/durable/schemas/factory.js +2356 -0
- package/build/services/durable/search.js +8 -8
- package/build/services/durable/worker.js +117 -25
- package/build/services/durable/workflow.d.ts +67 -52
- package/build/services/durable/workflow.js +322 -306
- package/build/services/engine/index.d.ts +2 -2
- package/build/services/engine/index.js +5 -2
- package/build/services/exporter/index.d.ts +2 -4
- package/build/services/exporter/index.js +4 -5
- package/build/services/hotmesh/index.d.ts +2 -2
- package/build/services/hotmesh/index.js +2 -2
- package/build/services/mapper/index.d.ts +6 -2
- package/build/services/mapper/index.js +6 -2
- package/build/services/pipe/functions/array.d.ts +2 -10
- package/build/services/pipe/functions/array.js +30 -28
- package/build/services/pipe/functions/conditional.d.ts +1 -0
- package/build/services/pipe/functions/conditional.js +3 -0
- package/build/services/pipe/functions/date.d.ts +1 -0
- package/build/services/pipe/functions/date.js +4 -0
- package/build/services/pipe/functions/index.d.ts +2 -0
- package/build/services/pipe/functions/index.js +2 -0
- package/build/services/pipe/functions/logical.d.ts +5 -0
- package/build/services/pipe/functions/logical.js +12 -0
- package/build/services/pipe/functions/object.d.ts +3 -0
- package/build/services/pipe/functions/object.js +25 -7
- package/build/services/pipe/index.d.ts +20 -3
- package/build/services/pipe/index.js +82 -16
- package/build/services/router/index.js +14 -3
- package/build/services/serializer/index.d.ts +3 -2
- package/build/services/serializer/index.js +11 -4
- package/build/services/store/clients/ioredis.js +6 -6
- package/build/services/store/clients/redis.js +7 -7
- package/build/services/store/index.d.ts +2 -0
- package/build/services/store/index.js +4 -1
- package/build/services/stream/clients/ioredis.js +8 -8
- package/build/services/stream/clients/redis.js +1 -1
- package/build/types/activity.d.ts +60 -5
- package/build/types/durable.d.ts +183 -36
- package/build/types/error.d.ts +48 -0
- package/build/types/error.js +2 -0
- package/build/types/exporter.d.ts +35 -7
- package/build/types/index.d.ts +4 -3
- package/build/types/job.d.ts +93 -6
- package/build/types/pipe.d.ts +81 -3
- package/build/types/stream.d.ts +61 -1
- package/build/types/stream.js +4 -0
- package/index.ts +1 -2
- package/modules/enums.ts +16 -8
- package/modules/errors.ts +139 -34
- package/package.json +7 -2
- package/services/activities/activity.ts +63 -14
- package/services/activities/await.ts +6 -6
- package/services/activities/cycle.ts +7 -6
- package/services/activities/hook.ts +12 -5
- package/services/activities/interrupt.ts +19 -9
- package/services/activities/signal.ts +6 -5
- package/services/activities/trigger.ts +43 -6
- package/services/activities/worker.ts +7 -7
- package/services/compiler/deployer.ts +33 -6
- package/services/compiler/validator.ts +7 -3
- package/services/durable/client.ts +49 -22
- package/services/durable/exporter.ts +162 -349
- package/services/durable/handle.ts +66 -53
- package/services/durable/index.ts +0 -2
- package/services/durable/schemas/factory.ts +2358 -0
- package/services/durable/search.ts +8 -8
- package/services/durable/worker.ts +128 -29
- package/services/durable/workflow.ts +371 -322
- package/services/engine/index.ts +8 -3
- package/services/exporter/index.ts +10 -12
- package/services/hotmesh/index.ts +4 -3
- package/services/mapper/index.ts +6 -2
- package/services/pipe/functions/array.ts +24 -37
- package/services/pipe/functions/conditional.ts +4 -0
- package/services/pipe/functions/date.ts +6 -0
- package/services/pipe/functions/index.ts +7 -5
- package/services/pipe/functions/logical.ts +11 -0
- package/services/pipe/functions/object.ts +26 -7
- package/services/pipe/index.ts +99 -21
- package/services/quorum/index.ts +1 -3
- package/services/router/index.ts +14 -3
- package/services/serializer/index.ts +12 -5
- package/services/store/clients/ioredis.ts +6 -6
- package/services/store/clients/redis.ts +7 -7
- package/services/store/index.ts +4 -1
- package/services/stream/clients/ioredis.ts +8 -8
- package/services/stream/clients/redis.ts +1 -1
- package/types/activity.ts +87 -15
- package/types/durable.ts +263 -75
- package/types/error.ts +52 -0
- package/types/exporter.ts +43 -9
- package/types/index.ts +14 -8
- package/types/job.ts +157 -36
- package/types/pipe.ts +84 -3
- package/types/stream.ts +82 -23
- package/build/services/durable/factory.d.ts +0 -17
- package/build/services/durable/factory.js +0 -817
- package/build/services/durable/meshos.d.ts +0 -127
- package/build/services/durable/meshos.js +0 -380
- package/services/durable/factory.ts +0 -818
- package/services/durable/meshos.ts +0 -441
|
@@ -54,8 +54,8 @@ export class Search {
|
|
|
54
54
|
const hotMeshPrefix = KeyService.mintKey(hotMeshClient.namespace, KeyType.JOB_STATE, keyParams);
|
|
55
55
|
const prefixes = search.prefix.map((prefix) => `${hotMeshPrefix}${prefix}`);
|
|
56
56
|
await store.exec('FT.CREATE', `${search.index}`, 'ON', 'HASH', 'PREFIX', prefixes.length.toString(), ...prefixes, 'SCHEMA', ...schema);
|
|
57
|
-
} catch (
|
|
58
|
-
hotMeshClient.engine.logger.info('durable-client-search-err', {
|
|
57
|
+
} catch (error) {
|
|
58
|
+
hotMeshClient.engine.logger.info('durable-client-search-err', { ...error });
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -71,8 +71,8 @@ export class Search {
|
|
|
71
71
|
const store = hotMeshClient.engine.store;
|
|
72
72
|
const searchIndexes = await store.exec('FT._LIST');
|
|
73
73
|
return searchIndexes as string[];
|
|
74
|
-
} catch (
|
|
75
|
-
hotMeshClient.engine.logger.info('durable-client-search-list-err', {
|
|
74
|
+
} catch (error) {
|
|
75
|
+
hotMeshClient.engine.logger.info('durable-client-search-list-err', { ...error });
|
|
76
76
|
return [];
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -113,8 +113,8 @@ export class Search {
|
|
|
113
113
|
async get(key: string): Promise<string> {
|
|
114
114
|
try {
|
|
115
115
|
return await this.store.exec('HGET',this.jobId, this.safeKey(key)) as string;
|
|
116
|
-
} catch (
|
|
117
|
-
this.hotMeshClient.logger.error('durable-search-get-error', {
|
|
116
|
+
} catch (error) {
|
|
117
|
+
this.hotMeshClient.logger.error('durable-search-get-error', { ...error });
|
|
118
118
|
return '';
|
|
119
119
|
}
|
|
120
120
|
}
|
|
@@ -126,8 +126,8 @@ export class Search {
|
|
|
126
126
|
}
|
|
127
127
|
try {
|
|
128
128
|
return await this.store.exec('HMGET', this.jobId, ...safeArgs) as string[];
|
|
129
|
-
} catch (
|
|
130
|
-
this.hotMeshClient.logger.error('durable-search-mget-error', {
|
|
129
|
+
} catch (error) {
|
|
130
|
+
this.hotMeshClient.logger.error('durable-search-mget-error', { ...error });
|
|
131
131
|
return [];
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
+
import ms from 'ms';
|
|
1
2
|
import {
|
|
3
|
+
HMSH_CODE_DURABLE_ALL,
|
|
4
|
+
HMSH_CODE_DURABLE_RETRYABLE,
|
|
5
|
+
HMSH_DURABLE_EXP_BACKOFF,
|
|
6
|
+
HMSH_DURABLE_MAX_INTERVAL,
|
|
7
|
+
HMSH_DURABLE_MAX_ATTEMPTS,
|
|
8
|
+
HMSH_LOGLEVEL } from '../../modules/enums';
|
|
9
|
+
import {
|
|
10
|
+
DurableChildError,
|
|
2
11
|
DurableFatalError,
|
|
3
|
-
DurableIncompleteSignalError,
|
|
4
12
|
DurableMaxedError,
|
|
13
|
+
DurableProxyError,
|
|
5
14
|
DurableRetryError,
|
|
6
|
-
|
|
15
|
+
DurableSleepError,
|
|
7
16
|
DurableTimeoutError,
|
|
8
|
-
|
|
17
|
+
DurableWaitForError } from '../../modules/errors';
|
|
9
18
|
import { asyncLocalStorage } from '../../modules/storage';
|
|
10
|
-
import { APP_ID, APP_VERSION, getWorkflowYAML } from './factory';
|
|
19
|
+
import { APP_ID, APP_VERSION, getWorkflowYAML } from './schemas/factory';
|
|
11
20
|
import { HotMeshService as HotMesh } from '../hotmesh';
|
|
12
21
|
import {
|
|
13
22
|
ActivityWorkflowDataType,
|
|
@@ -22,7 +31,7 @@ import {
|
|
|
22
31
|
StreamData,
|
|
23
32
|
StreamDataResponse,
|
|
24
33
|
StreamStatus } from '../../types/stream';
|
|
25
|
-
import {
|
|
34
|
+
import { formatISODate } from '../../modules/utils';
|
|
26
35
|
|
|
27
36
|
export class WorkerService {
|
|
28
37
|
static activityRegistry: Registry = {}; //user's activities
|
|
@@ -135,6 +144,7 @@ export class WorkerService {
|
|
|
135
144
|
return hotMeshWorker;
|
|
136
145
|
}
|
|
137
146
|
|
|
147
|
+
//this is the linked worker function in the reentrant workflow test
|
|
138
148
|
wrapActivityFunctions(): Function {
|
|
139
149
|
return async (data: StreamData): Promise<StreamDataResponse> => {
|
|
140
150
|
try {
|
|
@@ -150,17 +160,42 @@ export class WorkerService {
|
|
|
150
160
|
data: { response: pojoResponse }
|
|
151
161
|
};
|
|
152
162
|
} catch (err) {
|
|
153
|
-
this.activityRunner.engine.logger.error('durable-worker-activity-err', err);
|
|
163
|
+
this.activityRunner.engine.logger.error('durable-worker-activity-err', { name: err.name, message: err.message, stack: err.stack });
|
|
154
164
|
if (!(err instanceof DurableTimeoutError) &&
|
|
155
165
|
!(err instanceof DurableMaxedError) &&
|
|
156
166
|
!(err instanceof DurableFatalError)) {
|
|
157
|
-
|
|
167
|
+
|
|
168
|
+
//use code 599 as a proxy for all retryable errors
|
|
169
|
+
// (basically anything not 596, 597, 598)
|
|
170
|
+
return {
|
|
171
|
+
status: StreamStatus.SUCCESS,
|
|
172
|
+
code: HMSH_CODE_DURABLE_RETRYABLE,
|
|
173
|
+
metadata: { ...data.metadata },
|
|
174
|
+
data: {
|
|
175
|
+
$error: {
|
|
176
|
+
message: err.message,
|
|
177
|
+
stack: err.stack,
|
|
178
|
+
timestamp: formatISODate(new Date()),
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
} as StreamDataResponse;
|
|
158
182
|
}
|
|
183
|
+
|
|
159
184
|
return {
|
|
160
|
-
|
|
185
|
+
//always returrn success (the Durable module is just fine);
|
|
186
|
+
// it's the user's function that has failed
|
|
187
|
+
status: StreamStatus.SUCCESS,
|
|
161
188
|
code: err.code,
|
|
189
|
+
stack: err.stack,
|
|
162
190
|
metadata: { ...data.metadata },
|
|
163
|
-
data: {
|
|
191
|
+
data: {
|
|
192
|
+
$error: {
|
|
193
|
+
message: err.message,
|
|
194
|
+
stack: err.stack,
|
|
195
|
+
timestamp: formatISODate(new Date()),
|
|
196
|
+
code: err.code,
|
|
197
|
+
}
|
|
198
|
+
},
|
|
164
199
|
} as StreamDataResponse;
|
|
165
200
|
}
|
|
166
201
|
}
|
|
@@ -196,15 +231,17 @@ export class WorkerService {
|
|
|
196
231
|
|
|
197
232
|
wrapWorkflowFunction(workflowFunction: Function, workflowTopic: string, config: WorkerConfig): Function {
|
|
198
233
|
return async (data: StreamData): Promise<StreamDataResponse> => {
|
|
199
|
-
|
|
234
|
+
const counter = { counter: 0 };
|
|
235
|
+
const interruptionRegistry: any[] = [];
|
|
200
236
|
try {
|
|
201
237
|
//incoming data payload has arguments and workflowId
|
|
202
238
|
const workflowInput = data.data as unknown as WorkflowDataType;
|
|
203
239
|
const context = new Map();
|
|
204
|
-
context.set('
|
|
205
|
-
context.set('namespace', config.namespace ?? APP_ID);
|
|
240
|
+
context.set('canRetry', workflowInput.canRetry);
|
|
206
241
|
context.set('counter', counter);
|
|
207
|
-
context.set('
|
|
242
|
+
context.set('interruptionRegistry', interruptionRegistry);
|
|
243
|
+
context.set('namespace', config.namespace ?? APP_ID);
|
|
244
|
+
context.set('raw', data);
|
|
208
245
|
context.set('workflowId', workflowInput.workflowId);
|
|
209
246
|
if (workflowInput.originJobId) {
|
|
210
247
|
//if present there is an origin job to which this job is subordinated;
|
|
@@ -219,8 +256,8 @@ export class WorkerService {
|
|
|
219
256
|
context.set('workflowDimension', workflowInput.workflowDimension);
|
|
220
257
|
replayQuery = `-*${workflowInput.workflowDimension}-*`;
|
|
221
258
|
} else {
|
|
222
|
-
//last letter of words like 'hook', 'sleep', 'wait', 'signal', 'search', 'start'
|
|
223
|
-
replayQuery = '-*[
|
|
259
|
+
//last letter of words like 'hook', 'sleep', 'wait', 'signal', 'search', 'start', 'proxy', 'child', 'collator'
|
|
260
|
+
replayQuery = '-*[ehklptydr]-*';
|
|
224
261
|
}
|
|
225
262
|
context.set('workflowTopic', workflowTopic);
|
|
226
263
|
context.set('workflowName', workflowTopic.split('-').pop());
|
|
@@ -245,50 +282,112 @@ export class WorkerService {
|
|
|
245
282
|
data: { response: workflowResponse, done: true }
|
|
246
283
|
};
|
|
247
284
|
} catch (err) {
|
|
248
|
-
|
|
249
|
-
|
|
285
|
+
if (err instanceof DurableWaitForError || interruptionRegistry.length > 1) {
|
|
286
|
+
|
|
287
|
+
//NOTE: this type is spawned when `Promise.all` is used OR if the interruption is a `waitFor`
|
|
288
|
+
const workflowInput = data.data as unknown as WorkflowDataType;
|
|
289
|
+
const execIndex = counter.counter - interruptionRegistry.length + 1;
|
|
290
|
+
const { workflowId, workflowTopic, workflowDimension, originJobId } = workflowInput;
|
|
291
|
+
const collatorFlowId = `-${workflowId}-$${workflowDimension || ''}-$${execIndex}`;
|
|
292
|
+
return {
|
|
293
|
+
status: StreamStatus.SUCCESS,
|
|
294
|
+
code: HMSH_CODE_DURABLE_ALL,
|
|
295
|
+
metadata: { ...data.metadata },
|
|
296
|
+
data: {
|
|
297
|
+
code: HMSH_CODE_DURABLE_ALL,
|
|
298
|
+
items: [...interruptionRegistry],
|
|
299
|
+
size: interruptionRegistry.length,
|
|
300
|
+
workflowDimension: workflowDimension || '',
|
|
301
|
+
index: execIndex,
|
|
302
|
+
originJobId: originJobId || workflowId,
|
|
303
|
+
parentWorkflowId: workflowId,
|
|
304
|
+
workflowId: collatorFlowId,
|
|
305
|
+
workflowTopic: workflowTopic,
|
|
306
|
+
},
|
|
307
|
+
} as StreamDataResponse;
|
|
308
|
+
|
|
309
|
+
} else if (err instanceof DurableSleepError) {
|
|
310
|
+
//return the sleep interruption
|
|
250
311
|
return {
|
|
251
312
|
status: StreamStatus.SUCCESS,
|
|
252
313
|
code: err.code,
|
|
253
314
|
metadata: { ...data.metadata },
|
|
254
315
|
data: {
|
|
255
316
|
code: err.code,
|
|
256
|
-
message: JSON.stringify({ duration: err.duration, index: err.index,
|
|
317
|
+
message: JSON.stringify({ duration: err.duration, index: err.index, workflowDimension: err.workflowDimension }),
|
|
257
318
|
duration: err.duration,
|
|
258
319
|
index: err.index,
|
|
259
|
-
|
|
320
|
+
workflowDimension: err.workflowDimension,
|
|
260
321
|
}
|
|
261
322
|
} as StreamDataResponse;
|
|
262
323
|
|
|
263
|
-
|
|
264
|
-
|
|
324
|
+
} else if (err instanceof DurableProxyError) {
|
|
325
|
+
//return the proxyActivity interruption
|
|
265
326
|
return {
|
|
266
327
|
status: StreamStatus.SUCCESS,
|
|
267
328
|
code: err.code,
|
|
268
329
|
metadata: { ...data.metadata },
|
|
269
330
|
data: {
|
|
270
331
|
code: err.code,
|
|
271
|
-
|
|
272
|
-
|
|
332
|
+
message: JSON.stringify({ message: err.message, workflowId: err.workflowId, activityName: err.activityName, dimension: err.workflowDimension }),
|
|
333
|
+
arguments: err.arguments,
|
|
334
|
+
workflowDimension: err.workflowDimension,
|
|
335
|
+
index: err.index,
|
|
336
|
+
originJobId: err.originJobId,
|
|
337
|
+
parentWorkflowId: err.parentWorkflowId,
|
|
338
|
+
workflowId: err.workflowId,
|
|
339
|
+
workflowTopic: err.workflowTopic,
|
|
340
|
+
activityName: err.activityName,
|
|
341
|
+
backoffCoefficient: err.backoffCoefficient,
|
|
342
|
+
maximumAttempts: err.maximumAttempts,
|
|
343
|
+
maximumInterval: err.maximumInterval,
|
|
273
344
|
}
|
|
274
345
|
} as StreamDataResponse;
|
|
275
346
|
|
|
276
|
-
|
|
277
|
-
|
|
347
|
+
} else if (err instanceof DurableChildError) {
|
|
348
|
+
//return the child interruption
|
|
349
|
+
const msg = {
|
|
350
|
+
message: err.message,
|
|
351
|
+
workflowId: err.workflowId,
|
|
352
|
+
dimension: err.workflowDimension
|
|
353
|
+
};
|
|
278
354
|
return {
|
|
279
355
|
status: StreamStatus.SUCCESS,
|
|
280
356
|
code: err.code,
|
|
281
357
|
metadata: { ...data.metadata },
|
|
282
|
-
data: {
|
|
358
|
+
data: {
|
|
359
|
+
arguments: err.arguments,
|
|
360
|
+
await: err.await,
|
|
361
|
+
backoffCoefficient: err.backoffCoefficient || HMSH_DURABLE_EXP_BACKOFF ,
|
|
362
|
+
code: err.code,
|
|
363
|
+
index: err.index,
|
|
364
|
+
message: JSON.stringify(msg),
|
|
365
|
+
maximumAttempts: err.maximumAttempts || HMSH_DURABLE_MAX_ATTEMPTS,
|
|
366
|
+
maximumInterval: err.maximumInterval || ms(HMSH_DURABLE_MAX_INTERVAL) / 1000,
|
|
367
|
+
originJobId: err.originJobId,
|
|
368
|
+
parentWorkflowId: err.parentWorkflowId,
|
|
369
|
+
workflowDimension: err.workflowDimension,
|
|
370
|
+
workflowId: err.workflowId,
|
|
371
|
+
workflowTopic: err.workflowTopic,
|
|
372
|
+
}
|
|
283
373
|
} as StreamDataResponse;
|
|
284
374
|
}
|
|
285
375
|
|
|
286
|
-
//
|
|
376
|
+
// ALL other errors are actual fatal errors (598, 597, 596)
|
|
377
|
+
// OR will be retried (599)
|
|
287
378
|
return {
|
|
288
|
-
status: StreamStatus.
|
|
379
|
+
status: StreamStatus.SUCCESS,
|
|
289
380
|
code: err.code || new DurableRetryError(err.message).code,
|
|
290
381
|
metadata: { ...data.metadata },
|
|
291
|
-
data: {
|
|
382
|
+
data: {
|
|
383
|
+
$error: {
|
|
384
|
+
message: err.message,
|
|
385
|
+
type: err.name,
|
|
386
|
+
name: err.name,
|
|
387
|
+
stack: err.stack,
|
|
388
|
+
code: err.code || new DurableRetryError(err.message).code,
|
|
389
|
+
}
|
|
390
|
+
}
|
|
292
391
|
} as StreamDataResponse;
|
|
293
392
|
}
|
|
294
393
|
}
|