@hotmeshio/hotmesh 0.0.52 → 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 +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 +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 +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 +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 +63 -14
- 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
|
@@ -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
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import ms from 'ms';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
APP_ID,
|
|
5
|
+
APP_VERSION,
|
|
6
|
+
getWorkflowYAML } from './schemas/factory';
|
|
7
|
+
import {
|
|
8
|
+
HMSH_LOGLEVEL,
|
|
9
|
+
HMSH_EXPIRE_JOB_SECONDS,
|
|
10
|
+
HMSH_QUORUM_DELAY_MS,
|
|
11
|
+
HMSH_DURABLE_EXP_BACKOFF,
|
|
12
|
+
HMSH_DURABLE_MAX_ATTEMPTS,
|
|
13
|
+
HMSH_DURABLE_MAX_INTERVAL } from '../../modules/enums';
|
|
14
|
+
import { sleepFor } from '../../modules/utils';
|
|
2
15
|
import { WorkflowHandleService } from './handle';
|
|
3
16
|
import { HotMeshService as HotMesh } from '../hotmesh';
|
|
4
17
|
import {
|
|
@@ -11,8 +24,6 @@ import { JobState } from '../../types/job';
|
|
|
11
24
|
import { KeyService, KeyType } from '../../modules/key';
|
|
12
25
|
import { Search } from './search';
|
|
13
26
|
import { StreamStatus } from '../../types';
|
|
14
|
-
import { HMSH_LOGLEVEL, HMSH_EXPIRE_JOB_SECONDS, HMSH_QUORUM_DELAY_MS } from '../../modules/enums';
|
|
15
|
-
import { sleepFor } from '../../modules/utils';
|
|
16
27
|
|
|
17
28
|
export class ClientService {
|
|
18
29
|
|
|
@@ -32,7 +43,7 @@ export class ClientService {
|
|
|
32
43
|
await this.verifyWorkflowActive(hotMeshClient, targetNS);
|
|
33
44
|
if (!ClientService.topics.includes(workflowTopic)) {
|
|
34
45
|
ClientService.topics.push(workflowTopic);
|
|
35
|
-
await
|
|
46
|
+
await ClientService.createStream(hotMeshClient, workflowTopic, namespace);
|
|
36
47
|
}
|
|
37
48
|
return hotMeshClient;
|
|
38
49
|
}
|
|
@@ -49,7 +60,7 @@ export class ClientService {
|
|
|
49
60
|
}
|
|
50
61
|
});
|
|
51
62
|
ClientService.instances.set(targetNS, hotMeshClient);
|
|
52
|
-
await
|
|
63
|
+
await ClientService.createStream(await hotMeshClient, workflowTopic, namespace);
|
|
53
64
|
await this.activateWorkflow(await hotMeshClient, targetNS);
|
|
54
65
|
return hotMeshClient;
|
|
55
66
|
}
|
|
@@ -60,7 +71,7 @@ export class ClientService {
|
|
|
60
71
|
* has not yet been initialized, so this call ensures that the channel
|
|
61
72
|
* exists and is ready to serve as a container for events.
|
|
62
73
|
*/
|
|
63
|
-
createStream = async(hotMeshClient: HotMesh, workflowTopic: string, namespace?: string) => {
|
|
74
|
+
static createStream = async(hotMeshClient: HotMesh, workflowTopic: string, namespace?: string) => {
|
|
64
75
|
const store = hotMeshClient.engine.store;
|
|
65
76
|
const params = { appId: namespace ?? APP_ID, topic: workflowTopic };
|
|
66
77
|
const streamKey = store.mintKey(KeyType.STREAMS, params);
|
|
@@ -71,6 +82,23 @@ export class ClientService {
|
|
|
71
82
|
}
|
|
72
83
|
}
|
|
73
84
|
|
|
85
|
+
/**
|
|
86
|
+
* It is possible for a client to invoke a workflow without first
|
|
87
|
+
* creating the stream. This method will verify that the stream
|
|
88
|
+
* exists and if not, create it.
|
|
89
|
+
*/
|
|
90
|
+
static verifyStream = async(workflowTopic: string, namespace?: string) => {
|
|
91
|
+
const targetNS = namespace ?? APP_ID;
|
|
92
|
+
if (ClientService.instances.has(targetNS)) {
|
|
93
|
+
const hotMeshClient = await ClientService.instances.get(targetNS);
|
|
94
|
+
if (!ClientService.topics.includes(workflowTopic)) {
|
|
95
|
+
ClientService.topics.push(workflowTopic);
|
|
96
|
+
await ClientService.createStream(hotMeshClient, workflowTopic, namespace);
|
|
97
|
+
}
|
|
98
|
+
return hotMeshClient;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
74
102
|
/**
|
|
75
103
|
* For those deployments with a redis stack backend (with the FT module),
|
|
76
104
|
* this method will configure the search index for the workflow.
|
|
@@ -95,8 +123,8 @@ export class ClientService {
|
|
|
95
123
|
const hotMeshPrefix = KeyService.mintKey(hotMeshClient.namespace, KeyType.JOB_STATE, keyParams);
|
|
96
124
|
const prefixes = search.prefix.map((prefix) => `${hotMeshPrefix}${prefix}`);
|
|
97
125
|
await store.exec('FT.CREATE', `${search.index}`, 'ON', 'HASH', 'PREFIX', prefixes.length, ...prefixes, 'SCHEMA', ...schema);
|
|
98
|
-
} catch (
|
|
99
|
-
hotMeshClient.engine.logger.info('durable-client-search-err', {
|
|
126
|
+
} catch (error) {
|
|
127
|
+
hotMeshClient.engine.logger.info('durable-client-search-err', { ...error });
|
|
100
128
|
}
|
|
101
129
|
}
|
|
102
130
|
}
|
|
@@ -127,8 +155,11 @@ export class ClientService {
|
|
|
127
155
|
parentWorkflowId: options.parentWorkflowId,
|
|
128
156
|
workflowId: options.workflowId || HotMesh.guid(),
|
|
129
157
|
workflowTopic: workflowTopic,
|
|
130
|
-
backoffCoefficient: options.config?.backoffCoefficient ||
|
|
158
|
+
backoffCoefficient: options.config?.backoffCoefficient || HMSH_DURABLE_EXP_BACKOFF,
|
|
159
|
+
maximumAttempts: options.config?.maximumAttempts || HMSH_DURABLE_MAX_ATTEMPTS,
|
|
160
|
+
maximumInterval: ms(options.config?.maximumInterval || HMSH_DURABLE_MAX_INTERVAL) / 1000,
|
|
131
161
|
}
|
|
162
|
+
|
|
132
163
|
const context = { metadata: { trc, spn }, data: {}};
|
|
133
164
|
const jobId = await hotMeshClient.pub(
|
|
134
165
|
`${options.namespace ?? APP_ID}.execute`,
|
|
@@ -165,7 +196,9 @@ export class ClientService {
|
|
|
165
196
|
arguments: [...options.args],
|
|
166
197
|
id: options.workflowId,
|
|
167
198
|
workflowTopic,
|
|
168
|
-
backoffCoefficient: options.config?.backoffCoefficient ||
|
|
199
|
+
backoffCoefficient: options.config?.backoffCoefficient || HMSH_DURABLE_EXP_BACKOFF,
|
|
200
|
+
maximumAttempts: options.config?.maximumAttempts || HMSH_DURABLE_MAX_ATTEMPTS,
|
|
201
|
+
maximumInterval: ms(options.config?.maximumInterval || HMSH_DURABLE_MAX_INTERVAL) / 1000,
|
|
169
202
|
}
|
|
170
203
|
//seed search data if presentthe hook before entering
|
|
171
204
|
const hotMeshClient = await this.getHotMeshClient(workflowTopic, options.namespace);
|
|
@@ -190,9 +223,9 @@ export class ClientService {
|
|
|
190
223
|
const hotMeshClient = await this.getHotMeshClient(workflowTopic, namespace);
|
|
191
224
|
try {
|
|
192
225
|
return await this.search(hotMeshClient, index, query);
|
|
193
|
-
} catch (
|
|
194
|
-
hotMeshClient.engine.logger.error('durable-client-search-err', {
|
|
195
|
-
throw
|
|
226
|
+
} catch (error) {
|
|
227
|
+
hotMeshClient.engine.logger.error('durable-client-search-err', { ...error });
|
|
228
|
+
throw error;
|
|
196
229
|
}
|
|
197
230
|
}
|
|
198
231
|
}
|
|
@@ -218,7 +251,7 @@ export class ClientService {
|
|
|
218
251
|
await hotMesh.deploy(getWorkflowYAML(appId, version));
|
|
219
252
|
await hotMesh.activate(version);
|
|
220
253
|
} catch (error) {
|
|
221
|
-
hotMesh.engine.logger.error('durable-client-deploy-activate-err', { error });
|
|
254
|
+
hotMesh.engine.logger.error('durable-client-deploy-activate-err', { ...error });
|
|
222
255
|
throw error;
|
|
223
256
|
}
|
|
224
257
|
} else if(app && !app.active) {
|