@hotmeshio/hotmesh 0.0.51 → 0.0.53
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 +13 -9
- 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 +98 -18
- 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 +65 -16
- 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 +4 -4
- 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.js +12 -3
- 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 +56 -30
- package/build/services/durable/exporter.d.ts +7 -72
- package/build/services/durable/exporter.js +105 -295
- package/build/services/durable/handle.d.ts +11 -6
- package/build/services/durable/handle.js +59 -46
- 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 +46 -43
- package/build/services/durable/workflow.js +273 -277
- package/build/services/engine/index.js +3 -0
- package/build/services/exporter/index.d.ts +2 -4
- package/build/services/exporter/index.js +4 -5
- 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 +168 -33
- package/build/types/exporter.d.ts +26 -4
- package/build/types/index.d.ts +2 -2
- package/build/types/job.d.ts +69 -5
- 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 +174 -32
- package/package.json +7 -2
- package/services/activities/activity.ts +67 -18
- package/services/activities/await.ts +6 -6
- package/services/activities/cycle.ts +7 -6
- package/services/activities/hook.ts +4 -4
- package/services/activities/interrupt.ts +19 -9
- package/services/activities/signal.ts +6 -5
- package/services/activities/trigger.ts +16 -4
- 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 +47 -14
- package/services/durable/exporter.ts +110 -318
- package/services/durable/handle.ts +63 -50
- 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 +304 -288
- package/services/engine/index.ts +4 -0
- package/services/exporter/index.ts +10 -12
- 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 +246 -73
- package/types/exporter.ts +31 -5
- package/types/index.ts +6 -7
- package/types/job.ts +130 -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
|
@@ -143,19 +143,19 @@ class Activity {
|
|
|
143
143
|
this.transitionAdjacent(multiResponse, telemetry);
|
|
144
144
|
} catch (error) {
|
|
145
145
|
if (error instanceof CollationError) {
|
|
146
|
-
this.logger.info('process-event-inactive-error', { error });
|
|
146
|
+
this.logger.info('process-event-inactive-error', { ...error });
|
|
147
147
|
return;
|
|
148
148
|
} else if (error instanceof InactiveJobError) {
|
|
149
|
-
this.logger.info('process-event-inactive-job-error', { error });
|
|
149
|
+
this.logger.info('process-event-inactive-job-error', { ...error });
|
|
150
150
|
return;
|
|
151
151
|
} else if (error instanceof GenerationalError) {
|
|
152
|
-
this.logger.info('process-event-generational-job-error', { error });
|
|
152
|
+
this.logger.info('process-event-generational-job-error', { ...error });
|
|
153
153
|
return;
|
|
154
154
|
} else if (error instanceof GetStateError) {
|
|
155
|
-
this.logger.info('process-event-get-job-error', {
|
|
155
|
+
this.logger.info('process-event-get-job-error', { ...error });
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
|
-
this.logger.error('activity-process-event-error', { error });
|
|
158
|
+
this.logger.error('activity-process-event-error', { ...error, message: error.message, stack: error.stack, name: error.name });
|
|
159
159
|
telemetry && telemetry.setActivityError(error.message);
|
|
160
160
|
throw error;
|
|
161
161
|
} finally {
|
|
@@ -191,6 +191,10 @@ class Activity {
|
|
|
191
191
|
async processError(telemetry: TelemetryService, type: string): Promise<MultiResponseFlags> {
|
|
192
192
|
this.bindActivityError(this.data);
|
|
193
193
|
this.adjacencyList = await this.filterAdjacent();
|
|
194
|
+
if (!this.adjacencyList.length) {
|
|
195
|
+
this.bindJobError(this.data);
|
|
196
|
+
}
|
|
197
|
+
this.mapJobData();
|
|
194
198
|
const multi = this.store.getMulti();
|
|
195
199
|
await this.setState(multi);
|
|
196
200
|
await CollatorService.notarizeCompletion(this, multi);
|
|
@@ -205,7 +209,7 @@ class Activity {
|
|
|
205
209
|
const attrs: StringScalarType = { 'app.job.jss': jobStatus };
|
|
206
210
|
//adjacencyList membership has already been set at this point (according to activity status)
|
|
207
211
|
const messageIds = await this.transition(this.adjacencyList, jobStatus);
|
|
208
|
-
if (messageIds
|
|
212
|
+
if (messageIds?.length) {
|
|
209
213
|
attrs['app.activity.mids'] = messageIds.join(',')
|
|
210
214
|
}
|
|
211
215
|
telemetry.setActivityAttributes(attrs);
|
|
@@ -223,7 +227,30 @@ class Activity {
|
|
|
223
227
|
mapJobData(): void {
|
|
224
228
|
if(this.config.job?.maps) {
|
|
225
229
|
const mapper = new MapperService(this.config.job.maps, this.context);
|
|
226
|
-
|
|
230
|
+
const output = mapper.mapRules();
|
|
231
|
+
if (output) {
|
|
232
|
+
for (const key in output) {
|
|
233
|
+
const f1 = key.indexOf('[');
|
|
234
|
+
//keys with array notation suffix `somekey[]` represent
|
|
235
|
+
//dynamically-keyed mappings whose `value` must be moved to the output.
|
|
236
|
+
//The `value` must be an object with keys appropriate to the
|
|
237
|
+
//notation type: `somekey[0] (array)`, `somekey[-] (mark)`, OR `somekey[_] (search)`
|
|
238
|
+
if (f1 > -1) {
|
|
239
|
+
const amount = key.substring(f1 + 1).split(']')[0];
|
|
240
|
+
if (!isNaN(Number(amount))) {
|
|
241
|
+
const left = key.substring(0, f1);
|
|
242
|
+
output[left] = output[key];
|
|
243
|
+
delete output[key];
|
|
244
|
+
} else if (amount === '-' || amount === '_') {
|
|
245
|
+
const obj = output[key];
|
|
246
|
+
Object.keys(obj).forEach((newKey) => {
|
|
247
|
+
output[newKey] = obj[newKey];
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
this.context.data = output;
|
|
227
254
|
}
|
|
228
255
|
}
|
|
229
256
|
|
|
@@ -249,10 +276,22 @@ class Activity {
|
|
|
249
276
|
//set timeout in support of hook and/or duplex
|
|
250
277
|
}
|
|
251
278
|
|
|
279
|
+
/**
|
|
280
|
+
* Any StreamMessage with a status of ERROR is bound to the activity
|
|
281
|
+
*/
|
|
252
282
|
bindActivityError(data: Record<string, unknown>): void {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
283
|
+
const md = this.context[this.metadata.aid].output.metadata;
|
|
284
|
+
md.err = JSON.stringify(this.data);
|
|
285
|
+
//(temporary...useful for mapping error parts in the app.yaml)
|
|
286
|
+
md.$error = { ...data, is_stream_error: true };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* unhandled activity errors (activities that return an ERROR StreamMessage
|
|
291
|
+
* status and have no adjacent children to transition to) are bound to the job
|
|
292
|
+
*/
|
|
293
|
+
bindJobError(data: Record<string, unknown>): void {
|
|
294
|
+
this.context.metadata.err = JSON.stringify({ ...data, is_stream_error: true });
|
|
256
295
|
}
|
|
257
296
|
|
|
258
297
|
async getTriggerConfig(): Promise<ActivityType> {
|
|
@@ -322,9 +361,9 @@ class Activity {
|
|
|
322
361
|
if (this.status === StreamStatus.ERROR) {
|
|
323
362
|
self.output.metadata.err = JSON.stringify(this.data);
|
|
324
363
|
}
|
|
325
|
-
|
|
326
|
-
self.output.metadata.ac =
|
|
327
|
-
|
|
364
|
+
const ts = formatISODate(new Date());
|
|
365
|
+
self.output.metadata.ac = ts;
|
|
366
|
+
self.output.metadata.au = ts;
|
|
328
367
|
self.output.metadata.atp = this.config.type;
|
|
329
368
|
if (this.config.subtype) {
|
|
330
369
|
self.output.metadata.stp = this.config.subtype;
|
|
@@ -344,6 +383,11 @@ class Activity {
|
|
|
344
383
|
state[path] = value;
|
|
345
384
|
}
|
|
346
385
|
}
|
|
386
|
+
for (let key in this.context?.data ?? {}) {
|
|
387
|
+
if (key.startsWith('-') || key.startsWith('_')) {
|
|
388
|
+
state[key] = this.context.data[key];
|
|
389
|
+
}
|
|
390
|
+
}
|
|
347
391
|
TelemetryService.bindJobTelemetryToState(state, this.config, this.context);
|
|
348
392
|
}
|
|
349
393
|
|
|
@@ -398,9 +442,9 @@ class Activity {
|
|
|
398
442
|
let { dad, jid } = this.context.metadata;
|
|
399
443
|
const dIds = CollatorService.getDimensionsById([...this.config.ancestors, this.metadata.aid], dad || '');
|
|
400
444
|
//`state` is a unidimensional hash; context is a tree
|
|
401
|
-
const [state,
|
|
445
|
+
const [state, _status] = await this.store.getState(jid, consumes, dIds);
|
|
402
446
|
this.context = restoreHierarchy(state) as JobState;
|
|
403
|
-
this.assertGenerationalId(this.context
|
|
447
|
+
this.assertGenerationalId(this.context?.metadata?.gid, gid);
|
|
404
448
|
this.initDimensionalAddress(dad);
|
|
405
449
|
this.initSelf(this.context);
|
|
406
450
|
this.initPolicies(this.context);
|
|
@@ -417,9 +461,9 @@ class Activity {
|
|
|
417
461
|
throw new GenerationalError(
|
|
418
462
|
jobGID,
|
|
419
463
|
msgGID,
|
|
420
|
-
this.context
|
|
421
|
-
this.context
|
|
422
|
-
this.context
|
|
464
|
+
this.context?.metadata?.jid ?? '',
|
|
465
|
+
this.context?.metadata?.aid ?? '',
|
|
466
|
+
this.context?.metadata?.dad ?? ''
|
|
423
467
|
);
|
|
424
468
|
}
|
|
425
469
|
}
|
|
@@ -443,6 +487,11 @@ class Activity {
|
|
|
443
487
|
if (!self.hook) {
|
|
444
488
|
self.hook = { };
|
|
445
489
|
}
|
|
490
|
+
if (!self.output.metadata) {
|
|
491
|
+
self.output.metadata = { };
|
|
492
|
+
}
|
|
493
|
+
//prebind the updated timestamp (mappings need the time)
|
|
494
|
+
self.output.metadata.au = formatISODate(new Date());
|
|
446
495
|
context['$self'] = self;
|
|
447
496
|
context['$job'] = context; //NEVER call STRINGIFY! (now circular)
|
|
448
497
|
return context as JobState;
|
|
@@ -2,9 +2,11 @@ import {
|
|
|
2
2
|
GenerationalError,
|
|
3
3
|
GetStateError,
|
|
4
4
|
InactiveJobError } from '../../modules/errors';
|
|
5
|
+
import { guid } from '../../modules/utils';
|
|
5
6
|
import { Activity } from './activity';
|
|
6
7
|
import { CollatorService } from '../collator';
|
|
7
8
|
import { EngineService } from '../engine';
|
|
9
|
+
import { Pipe } from '../pipe';
|
|
8
10
|
import { TelemetryService } from '../telemetry';
|
|
9
11
|
import {
|
|
10
12
|
ActivityData,
|
|
@@ -14,8 +16,6 @@ import {
|
|
|
14
16
|
import { JobState } from '../../types/job';
|
|
15
17
|
import { MultiResponseFlags, RedisMulti } from '../../types/redis';
|
|
16
18
|
import { StreamData, StreamDataType } from '../../types/stream';
|
|
17
|
-
import { Pipe } from '../pipe';
|
|
18
|
-
import { guid } from '../../modules/utils';
|
|
19
19
|
|
|
20
20
|
class Await extends Activity {
|
|
21
21
|
config: AwaitActivity;
|
|
@@ -60,16 +60,16 @@ class Await extends Activity {
|
|
|
60
60
|
return this.context.metadata.aid;
|
|
61
61
|
} catch (error) {
|
|
62
62
|
if (error instanceof InactiveJobError) {
|
|
63
|
-
this.logger.error('await-inactive-job-error', { error });
|
|
63
|
+
this.logger.error('await-inactive-job-error', { ...error });
|
|
64
64
|
return;
|
|
65
65
|
} else if (error instanceof GenerationalError) {
|
|
66
|
-
this.logger.info('process-event-generational-job-error', { error });
|
|
66
|
+
this.logger.info('process-event-generational-job-error', { ...error });
|
|
67
67
|
return;
|
|
68
68
|
} else if (error instanceof GetStateError) {
|
|
69
|
-
this.logger.error('await-get-state-error', { error });
|
|
69
|
+
this.logger.error('await-get-state-error', { ...error });
|
|
70
70
|
return;
|
|
71
71
|
} else {
|
|
72
|
-
this.logger.error('await-process-error', { error });
|
|
72
|
+
this.logger.error('await-process-error', { ...error });
|
|
73
73
|
}
|
|
74
74
|
telemetry.setActivityError(error.message);
|
|
75
75
|
throw error;
|
|
@@ -2,18 +2,19 @@ import {
|
|
|
2
2
|
GenerationalError,
|
|
3
3
|
GetStateError,
|
|
4
4
|
InactiveJobError } from '../../modules/errors';
|
|
5
|
+
import { guid } from '../../modules/utils';
|
|
5
6
|
import { CollatorService } from '../collator';
|
|
6
7
|
import { EngineService } from '../engine';
|
|
7
|
-
import { Activity
|
|
8
|
+
import { Activity } from './activity';
|
|
8
9
|
import {
|
|
9
10
|
ActivityData,
|
|
10
11
|
ActivityMetadata,
|
|
12
|
+
ActivityType,
|
|
11
13
|
CycleActivity } from '../../types/activity';
|
|
12
14
|
import { JobState } from '../../types/job';
|
|
13
15
|
import { MultiResponseFlags, RedisMulti } from '../../types/redis';
|
|
14
16
|
import { StreamData } from '../../types/stream';
|
|
15
17
|
import { TelemetryService } from '../telemetry';
|
|
16
|
-
import { guid } from '../../modules/utils';
|
|
17
18
|
|
|
18
19
|
class Cycle extends Activity {
|
|
19
20
|
config: CycleActivity;
|
|
@@ -63,16 +64,16 @@ class Cycle extends Activity {
|
|
|
63
64
|
return this.context.metadata.aid;
|
|
64
65
|
} catch (error) {
|
|
65
66
|
if (error instanceof InactiveJobError) {
|
|
66
|
-
this.logger.error('cycle-inactive-job-error', { error });
|
|
67
|
+
this.logger.error('cycle-inactive-job-error', { ...error });
|
|
67
68
|
return;
|
|
68
69
|
} else if (error instanceof GenerationalError) {
|
|
69
|
-
this.logger.info('process-event-generational-job-error', { error });
|
|
70
|
+
this.logger.info('process-event-generational-job-error', { ...error });
|
|
70
71
|
return;
|
|
71
72
|
} else if (error instanceof GetStateError) {
|
|
72
|
-
this.logger.error('cycle-get-state-error', { error });
|
|
73
|
+
this.logger.error('cycle-get-state-error', { ...error });
|
|
73
74
|
return;
|
|
74
75
|
} else {
|
|
75
|
-
this.logger.error('cycle-process-error', { error });
|
|
76
|
+
this.logger.error('cycle-process-error', { ...error });
|
|
76
77
|
}
|
|
77
78
|
telemetry.setActivityError(error.message);
|
|
78
79
|
throw error;
|
|
@@ -63,16 +63,16 @@ class Hook extends Activity {
|
|
|
63
63
|
return this.context.metadata.aid;
|
|
64
64
|
} catch (error) {
|
|
65
65
|
if (error instanceof InactiveJobError) {
|
|
66
|
-
this.logger.error('hook-inactive-job-error', { error });
|
|
66
|
+
this.logger.error('hook-inactive-job-error', { ...error });
|
|
67
67
|
return;
|
|
68
68
|
} else if (error instanceof GenerationalError) {
|
|
69
|
-
this.logger.info('process-event-generational-job-error', { error });
|
|
69
|
+
this.logger.info('process-event-generational-job-error', { ...error });
|
|
70
70
|
return;
|
|
71
71
|
} else if (error instanceof GetStateError) {
|
|
72
|
-
this.logger.error('hook-get-state-error', { error });
|
|
72
|
+
this.logger.error('hook-get-state-error', { ...error });
|
|
73
73
|
return;
|
|
74
74
|
} else {
|
|
75
|
-
this.logger.error('hook-process-error', { error });
|
|
75
|
+
this.logger.error('hook-process-error', { ...error });
|
|
76
76
|
}
|
|
77
77
|
telemetry.setActivityError(error.message);
|
|
78
78
|
throw error;
|
|
@@ -2,17 +2,18 @@ import {
|
|
|
2
2
|
GenerationalError,
|
|
3
3
|
GetStateError,
|
|
4
4
|
InactiveJobError } from '../../modules/errors';
|
|
5
|
+
import { CollatorService } from '../collator';
|
|
6
|
+
import { Activity } from './activity';
|
|
5
7
|
import { EngineService } from '../engine';
|
|
6
|
-
import {
|
|
8
|
+
import { Pipe } from '../pipe';
|
|
9
|
+
import { TelemetryService } from '../telemetry';
|
|
7
10
|
import {
|
|
8
11
|
ActivityData,
|
|
9
12
|
ActivityMetadata,
|
|
13
|
+
ActivityType,
|
|
10
14
|
InterruptActivity } from '../../types/activity';
|
|
11
|
-
import { MultiResponseFlags } from '../../types';
|
|
12
|
-
import { CollatorService } from '../collator';
|
|
13
15
|
import { JobInterruptOptions, JobState } from '../../types/job';
|
|
14
|
-
import {
|
|
15
|
-
import { Pipe } from '../pipe';
|
|
16
|
+
import { MultiResponseFlags } from '../../types/redis';
|
|
16
17
|
|
|
17
18
|
class Interrupt extends Activity {
|
|
18
19
|
config: InterruptActivity;
|
|
@@ -46,16 +47,16 @@ class Interrupt extends Activity {
|
|
|
46
47
|
}
|
|
47
48
|
} catch (error) {
|
|
48
49
|
if (error instanceof InactiveJobError) {
|
|
49
|
-
this.logger.error('interrupt-inactive-job-error', { error });
|
|
50
|
+
this.logger.error('interrupt-inactive-job-error', { ...error });
|
|
50
51
|
return;
|
|
51
52
|
} else if (error instanceof GenerationalError) {
|
|
52
|
-
this.logger.info('process-event-generational-job-error', { error });
|
|
53
|
+
this.logger.info('process-event-generational-job-error', { ...error });
|
|
53
54
|
return;
|
|
54
55
|
} else if (error instanceof GetStateError) {
|
|
55
|
-
this.logger.error('interrupt-get-state-error', { error });
|
|
56
|
+
this.logger.error('interrupt-get-state-error', { ...error });
|
|
56
57
|
return;
|
|
57
58
|
} else {
|
|
58
|
-
this.logger.error('interrupt-process-error', { error });
|
|
59
|
+
this.logger.error('interrupt-process-error', { ...error });
|
|
59
60
|
}
|
|
60
61
|
telemetry.setActivityError(error.message);
|
|
61
62
|
throw error;
|
|
@@ -142,6 +143,15 @@ class Interrupt extends Activity {
|
|
|
142
143
|
descend: this.config.descend !== undefined
|
|
143
144
|
? Pipe.resolve(this.config.descend, this.context)
|
|
144
145
|
: undefined,
|
|
146
|
+
code: this.config.code !== undefined
|
|
147
|
+
? Pipe.resolve(this.config.code, this.context)
|
|
148
|
+
: undefined,
|
|
149
|
+
expire: this.config.expire !== undefined
|
|
150
|
+
? Pipe.resolve(this.config.expire, this.context)
|
|
151
|
+
: undefined,
|
|
152
|
+
stack: this.config.stack !== undefined
|
|
153
|
+
? Pipe.resolve(this.config.stack, this.context)
|
|
154
|
+
: undefined,
|
|
145
155
|
};
|
|
146
156
|
}
|
|
147
157
|
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
GenerationalError,
|
|
3
3
|
GetStateError,
|
|
4
4
|
InactiveJobError } from '../../modules/errors';
|
|
5
|
-
import { Activity
|
|
5
|
+
import { Activity } from './activity';
|
|
6
6
|
import { CollatorService } from '../collator';
|
|
7
7
|
import { EngineService } from '../engine';
|
|
8
8
|
import { MapperService } from '../mapper';
|
|
@@ -11,6 +11,7 @@ import { TelemetryService } from '../telemetry';
|
|
|
11
11
|
import {
|
|
12
12
|
ActivityData,
|
|
13
13
|
ActivityMetadata,
|
|
14
|
+
ActivityType,
|
|
14
15
|
SignalActivity } from '../../types/activity';
|
|
15
16
|
import { JobState } from '../../types/job';
|
|
16
17
|
import { MultiResponseFlags } from '../../types/redis';
|
|
@@ -71,16 +72,16 @@ class Signal extends Activity {
|
|
|
71
72
|
return this.context.metadata.aid;
|
|
72
73
|
} catch (error) {
|
|
73
74
|
if (error instanceof InactiveJobError) {
|
|
74
|
-
this.logger.error('signal-inactive-job-error', { error });
|
|
75
|
+
this.logger.error('signal-inactive-job-error', { ...error });
|
|
75
76
|
return;
|
|
76
77
|
} else if (error instanceof GenerationalError) {
|
|
77
|
-
this.logger.info('process-event-generational-job-error', { error });
|
|
78
|
+
this.logger.info('process-event-generational-job-error', { ...error });
|
|
78
79
|
return;
|
|
79
80
|
} else if (error instanceof GetStateError) {
|
|
80
|
-
this.logger.error('signal-get-state-error', { error });
|
|
81
|
+
this.logger.error('signal-get-state-error', { ...error });
|
|
81
82
|
return;
|
|
82
83
|
} else {
|
|
83
|
-
this.logger.error('signal-process-error', { error });
|
|
84
|
+
this.logger.error('signal-process-error', { ...error });
|
|
84
85
|
}
|
|
85
86
|
telemetry.setActivityError(error.message);
|
|
86
87
|
throw error;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { DuplicateJobError } from '../../modules/errors';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
formatISODate,
|
|
4
|
+
getTimeSeries,
|
|
5
|
+
guid } from '../../modules/utils';
|
|
3
6
|
import { Activity } from './activity';
|
|
4
7
|
import { CollatorService } from '../collator';
|
|
5
8
|
import { EngineService } from '../engine';
|
|
@@ -67,9 +70,9 @@ class Trigger extends Activity {
|
|
|
67
70
|
return this.context.metadata.jid;
|
|
68
71
|
} catch (error) {
|
|
69
72
|
if (error instanceof DuplicateJobError) {
|
|
70
|
-
this.logger.error('duplicate-job-error', { error });
|
|
73
|
+
this.logger.error('duplicate-job-error', { job_id: error.jobId });
|
|
71
74
|
} else {
|
|
72
|
-
this.logger.error('trigger-process-error', { error });
|
|
75
|
+
this.logger.error('trigger-process-error', { ...error });
|
|
73
76
|
}
|
|
74
77
|
telemetry.setActivityError(error.message);
|
|
75
78
|
throw error;
|
|
@@ -86,7 +89,16 @@ class Trigger extends Activity {
|
|
|
86
89
|
|
|
87
90
|
async execAdjacentParent() {
|
|
88
91
|
if (this.context.metadata.px) {
|
|
89
|
-
|
|
92
|
+
const timestamp = formatISODate(new Date());
|
|
93
|
+
const jobStartedConfirmationMessage = {
|
|
94
|
+
metadata: this.context.metadata,
|
|
95
|
+
data: {
|
|
96
|
+
job_id: this.context.metadata.jid,
|
|
97
|
+
jc: timestamp,
|
|
98
|
+
ju: timestamp,
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
await this.engine.execAdjacentParent(this.context, jobStartedConfirmationMessage);
|
|
90
102
|
}
|
|
91
103
|
}
|
|
92
104
|
|
|
@@ -2,9 +2,12 @@ import {
|
|
|
2
2
|
GenerationalError,
|
|
3
3
|
GetStateError,
|
|
4
4
|
InactiveJobError } from '../../modules/errors';
|
|
5
|
+
import { guid } from '../../modules/utils';
|
|
5
6
|
import { Activity } from './activity';
|
|
6
7
|
import { CollatorService } from '../collator';
|
|
7
8
|
import { EngineService } from '../engine';
|
|
9
|
+
import { Pipe } from '../pipe';
|
|
10
|
+
import { TelemetryService } from '../telemetry';
|
|
8
11
|
import {
|
|
9
12
|
ActivityData,
|
|
10
13
|
ActivityMetadata,
|
|
@@ -13,9 +16,6 @@ import {
|
|
|
13
16
|
import { JobState } from '../../types/job';
|
|
14
17
|
import { MultiResponseFlags, RedisMulti } from '../../types/redis';
|
|
15
18
|
import { StreamData} from '../../types/stream';
|
|
16
|
-
import { TelemetryService } from '../telemetry';
|
|
17
|
-
import { Pipe } from '../pipe';
|
|
18
|
-
import { guid } from '../../modules/utils';
|
|
19
19
|
|
|
20
20
|
class Worker extends Activity {
|
|
21
21
|
config: WorkerActivity;
|
|
@@ -61,16 +61,16 @@ class Worker extends Activity {
|
|
|
61
61
|
return this.context.metadata.aid;
|
|
62
62
|
} catch (error) {
|
|
63
63
|
if (error instanceof InactiveJobError) {
|
|
64
|
-
this.logger.error('await-inactive-job-error', { error });
|
|
64
|
+
this.logger.error('await-inactive-job-error', { ...error });
|
|
65
65
|
return;
|
|
66
66
|
} else if (error instanceof GenerationalError) {
|
|
67
|
-
this.logger.info('process-event-generational-job-error', { error });
|
|
67
|
+
this.logger.info('process-event-generational-job-error', { ...error });
|
|
68
68
|
return;
|
|
69
69
|
} else if (error instanceof GetStateError) {
|
|
70
|
-
this.logger.error('worker-get-state-error', { error });
|
|
70
|
+
this.logger.error('worker-get-state-error', { ...error });
|
|
71
71
|
return;
|
|
72
72
|
} else {
|
|
73
|
-
this.logger.error('worker-process-error', { error });
|
|
73
|
+
this.logger.error('worker-process-error', { ...error });
|
|
74
74
|
}
|
|
75
75
|
telemetry.setActivityError(error.message);
|
|
76
76
|
throw error;
|
|
@@ -9,6 +9,7 @@ import { HotMeshGraph, HotMeshManifest } from '../../types/hotmesh';
|
|
|
9
9
|
import { RedisClient, RedisMulti } from '../../types/redis';
|
|
10
10
|
import { StringAnyType, Symbols } from '../../types/serializer';
|
|
11
11
|
import { Pipe } from '../pipe';
|
|
12
|
+
import { Validator } from './validator';
|
|
12
13
|
|
|
13
14
|
const DEFAULT_METADATA_RANGE_SIZE = 26; //metadata is 26 slots ([a-z] * 1)
|
|
14
15
|
const DEFAULT_DATA_RANGE_SIZE = 260; //data is 260 slots ([a-zA-Z] * 5)
|
|
@@ -201,6 +202,9 @@ class Deployer {
|
|
|
201
202
|
//DAGs have one parent; easy to optimize for
|
|
202
203
|
graph.activities[to].parent = fromActivity;
|
|
203
204
|
}
|
|
205
|
+
//temporarily bind the transitions to the parent activity,
|
|
206
|
+
// so the consumer/producer registrar picks up the bindings
|
|
207
|
+
graph.activities[fromActivity].transitions = toTransitions;
|
|
204
208
|
}
|
|
205
209
|
}
|
|
206
210
|
}
|
|
@@ -257,9 +261,29 @@ class Deployer {
|
|
|
257
261
|
let newPath = [...path, key];
|
|
258
262
|
traverse(obj[key], newPath);
|
|
259
263
|
} else {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
264
|
+
//wildcard mapping (e.g., 'friends[25]')
|
|
265
|
+
//when this is resolved, it will be expanded to
|
|
266
|
+
//`'friends/0', ..., 'friends/24'`, providing 25 dynamic
|
|
267
|
+
//slots in the flow's output data
|
|
268
|
+
const pathName = [...path, key].join('/');
|
|
269
|
+
if (!pathName.includes('[')) {
|
|
270
|
+
const finalPath = `data/${pathName}`;
|
|
271
|
+
if (!result.includes(finalPath)) {
|
|
272
|
+
result.push(finalPath);
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
const [left, right] = pathName.split('[');
|
|
276
|
+
//check if this variable isLiteralKeyType (#, -, or _)
|
|
277
|
+
const [amount, _] = right.split(']');
|
|
278
|
+
if (!isNaN(parseInt(amount))) {
|
|
279
|
+
//loop to create all possible paths (0 to amount)
|
|
280
|
+
for (let i = 0; i < parseInt(amount); i++) {
|
|
281
|
+
const finalPath = `data/${left}/${i}`;
|
|
282
|
+
if (!result.includes(finalPath)) {
|
|
283
|
+
result.push(finalPath);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
} //else ignore (amount might be '-' or '_') `-` is marker data; `_` is job data;
|
|
263
287
|
}
|
|
264
288
|
}
|
|
265
289
|
}
|
|
@@ -280,7 +304,7 @@ class Deployer {
|
|
|
280
304
|
trigger.PRODUCES = results;
|
|
281
305
|
}
|
|
282
306
|
}
|
|
283
|
-
|
|
307
|
+
|
|
284
308
|
resolveMappingDependencies() {
|
|
285
309
|
const dynamicMappingRules: string[] = [];
|
|
286
310
|
//recursive function to descend into the object and find all dynamic mapping rules
|
|
@@ -289,7 +313,7 @@ class Deployer {
|
|
|
289
313
|
if (typeof obj[key] === 'string') {
|
|
290
314
|
const stringValue = obj[key] as string;
|
|
291
315
|
const dynamicMappingRuleMatch = stringValue.match(/^\{[^@].*}$/);
|
|
292
|
-
if (dynamicMappingRuleMatch) {
|
|
316
|
+
if (dynamicMappingRuleMatch && !Validator.CONTEXT_VARS.includes(stringValue)) {
|
|
293
317
|
if (stringValue.split('.')[1] !== 'input') {
|
|
294
318
|
dynamicMappingRules.push(stringValue);
|
|
295
319
|
consumes.push(stringValue);
|
|
@@ -359,7 +383,10 @@ class Deployer {
|
|
|
359
383
|
for (const graph of graphs) {
|
|
360
384
|
const activities = graph.activities;
|
|
361
385
|
for (const activityKey in activities) {
|
|
362
|
-
|
|
386
|
+
const target = activities[activityKey];
|
|
387
|
+
//remove transitions; no longer necessary for runtime
|
|
388
|
+
delete target.transitions;
|
|
389
|
+
activitySchemas[activityKey] = target;
|
|
363
390
|
}
|
|
364
391
|
}
|
|
365
392
|
await this.store.setSchemas(activitySchemas, this.getVID());
|
|
@@ -11,7 +11,8 @@ class Validator {
|
|
|
11
11
|
store: StoreService<RedisClient, RedisMulti> | null = null;
|
|
12
12
|
|
|
13
13
|
static SYS_VARS = ['$app', '$self', '$graph', '$job'];
|
|
14
|
-
|
|
14
|
+
static CONTEXT_VARS = ['{$input}', '{$output}', '{$item}', '{$key}', '{$index}'];
|
|
15
|
+
|
|
15
16
|
constructor(manifest: HotMeshManifest) {
|
|
16
17
|
this.manifest = manifest;
|
|
17
18
|
}
|
|
@@ -92,8 +93,7 @@ class Validator {
|
|
|
92
93
|
if (statement.startsWith('{') && statement.endsWith('}')) {
|
|
93
94
|
const statementParts = statement.slice(1, -1).split('.');
|
|
94
95
|
const referencedActivityId = statementParts[0];
|
|
95
|
-
|
|
96
|
-
if (!(Validator.SYS_VARS.includes(referencedActivityId) || activityIds.includes(referencedActivityId) || this.isFunction(statement))) {
|
|
96
|
+
if (!(Validator.SYS_VARS.includes(referencedActivityId) || activityIds.includes(referencedActivityId) || this.isFunction(statement) || this.isContextVariable(statement))) {
|
|
97
97
|
throw new Error(`Mapping statement references non-existent activity: ${statement}`);
|
|
98
98
|
}
|
|
99
99
|
}
|
|
@@ -105,6 +105,10 @@ class Validator {
|
|
|
105
105
|
return value.startsWith('{@') && Pipe.resolveFunction(value);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
isContextVariable(value: string): boolean {
|
|
109
|
+
return ['{$input}', '{$output}', '{$item}', '{$key}', '{$index}'].includes(value);
|
|
110
|
+
}
|
|
111
|
+
|
|
108
112
|
// 1.3) Validate the mapping/@pipe statements are valid
|
|
109
113
|
validateMappingStatements() {
|
|
110
114
|
// Implement the method content
|