@hotmeshio/hotmesh 0.0.1
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/LICENSE +214 -0
- package/README.md +241 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +7 -0
- package/build/modules/errors.d.ts +28 -0
- package/build/modules/errors.js +50 -0
- package/build/modules/key.d.ts +75 -0
- package/build/modules/key.js +116 -0
- package/build/modules/utils.d.ts +34 -0
- package/build/modules/utils.js +173 -0
- package/build/package.json +73 -0
- package/build/services/activities/activity.d.ts +59 -0
- package/build/services/activities/activity.js +396 -0
- package/build/services/activities/await.d.ts +16 -0
- package/build/services/activities/await.js +143 -0
- package/build/services/activities/emit.d.ts +9 -0
- package/build/services/activities/emit.js +13 -0
- package/build/services/activities/index.d.ts +15 -0
- package/build/services/activities/index.js +16 -0
- package/build/services/activities/iterate.d.ts +9 -0
- package/build/services/activities/iterate.js +13 -0
- package/build/services/activities/trigger.d.ts +22 -0
- package/build/services/activities/trigger.js +161 -0
- package/build/services/activities/worker.d.ts +17 -0
- package/build/services/activities/worker.js +164 -0
- package/build/services/collator/index.d.ts +54 -0
- package/build/services/collator/index.js +171 -0
- package/build/services/compiler/deployer.d.ts +35 -0
- package/build/services/compiler/deployer.js +412 -0
- package/build/services/compiler/index.d.ts +30 -0
- package/build/services/compiler/index.js +111 -0
- package/build/services/compiler/validator.d.ts +32 -0
- package/build/services/compiler/validator.js +134 -0
- package/build/services/connector/clients/ioredis.d.ts +13 -0
- package/build/services/connector/clients/ioredis.js +50 -0
- package/build/services/connector/clients/redis.d.ts +13 -0
- package/build/services/connector/clients/redis.js +62 -0
- package/build/services/connector/index.d.ts +5 -0
- package/build/services/connector/index.js +31 -0
- package/build/services/dimension/index.d.ts +29 -0
- package/build/services/dimension/index.js +35 -0
- package/build/services/durable/asyncLocalStorage.d.ts +3 -0
- package/build/services/durable/asyncLocalStorage.js +5 -0
- package/build/services/durable/client.d.ts +15 -0
- package/build/services/durable/client.js +108 -0
- package/build/services/durable/connection.d.ts +4 -0
- package/build/services/durable/connection.js +51 -0
- package/build/services/durable/factory.d.ts +3 -0
- package/build/services/durable/factory.js +123 -0
- package/build/services/durable/handle.d.ts +8 -0
- package/build/services/durable/handle.js +38 -0
- package/build/services/durable/index.d.ts +57 -0
- package/build/services/durable/index.js +58 -0
- package/build/services/durable/native.d.ts +4 -0
- package/build/services/durable/native.js +47 -0
- package/build/services/durable/worker.d.ts +36 -0
- package/build/services/durable/worker.js +266 -0
- package/build/services/durable/workflow.d.ts +6 -0
- package/build/services/durable/workflow.js +135 -0
- package/build/services/engine/index.d.ts +82 -0
- package/build/services/engine/index.js +511 -0
- package/build/services/hotmesh/index.d.ts +45 -0
- package/build/services/hotmesh/index.js +134 -0
- package/build/services/logger/index.d.ts +17 -0
- package/build/services/logger/index.js +73 -0
- package/build/services/mapper/index.d.ts +24 -0
- package/build/services/mapper/index.js +72 -0
- package/build/services/pipe/functions/array.d.ts +24 -0
- package/build/services/pipe/functions/array.js +69 -0
- package/build/services/pipe/functions/bitwise.d.ts +9 -0
- package/build/services/pipe/functions/bitwise.js +24 -0
- package/build/services/pipe/functions/conditional.d.ts +10 -0
- package/build/services/pipe/functions/conditional.js +27 -0
- package/build/services/pipe/functions/date.d.ts +57 -0
- package/build/services/pipe/functions/date.js +167 -0
- package/build/services/pipe/functions/index.d.ts +25 -0
- package/build/services/pipe/functions/index.js +26 -0
- package/build/services/pipe/functions/json.d.ts +5 -0
- package/build/services/pipe/functions/json.js +12 -0
- package/build/services/pipe/functions/math.d.ts +38 -0
- package/build/services/pipe/functions/math.js +111 -0
- package/build/services/pipe/functions/number.d.ts +25 -0
- package/build/services/pipe/functions/number.js +133 -0
- package/build/services/pipe/functions/object.d.ts +22 -0
- package/build/services/pipe/functions/object.js +63 -0
- package/build/services/pipe/functions/string.d.ts +23 -0
- package/build/services/pipe/functions/string.js +69 -0
- package/build/services/pipe/functions/symbol.d.ts +12 -0
- package/build/services/pipe/functions/symbol.js +33 -0
- package/build/services/pipe/functions/unary.d.ts +7 -0
- package/build/services/pipe/functions/unary.js +18 -0
- package/build/services/pipe/index.d.ts +30 -0
- package/build/services/pipe/index.js +128 -0
- package/build/services/quorum/index.d.ts +34 -0
- package/build/services/quorum/index.js +147 -0
- package/build/services/reporter/index.d.ts +47 -0
- package/build/services/reporter/index.js +330 -0
- package/build/services/serializer/index.d.ts +36 -0
- package/build/services/serializer/index.js +222 -0
- package/build/services/signaler/store.d.ts +15 -0
- package/build/services/signaler/store.js +53 -0
- package/build/services/signaler/stream.d.ts +43 -0
- package/build/services/signaler/stream.js +317 -0
- package/build/services/store/cache.d.ts +66 -0
- package/build/services/store/cache.js +127 -0
- package/build/services/store/clients/ioredis.d.ts +27 -0
- package/build/services/store/clients/ioredis.js +96 -0
- package/build/services/store/clients/redis.d.ts +29 -0
- package/build/services/store/clients/redis.js +143 -0
- package/build/services/store/index.d.ts +88 -0
- package/build/services/store/index.js +657 -0
- package/build/services/stream/clients/ioredis.d.ts +23 -0
- package/build/services/stream/clients/ioredis.js +115 -0
- package/build/services/stream/clients/redis.d.ts +23 -0
- package/build/services/stream/clients/redis.js +119 -0
- package/build/services/stream/index.d.ts +21 -0
- package/build/services/stream/index.js +9 -0
- package/build/services/sub/clients/ioredis.d.ts +20 -0
- package/build/services/sub/clients/ioredis.js +72 -0
- package/build/services/sub/clients/redis.d.ts +20 -0
- package/build/services/sub/clients/redis.js +63 -0
- package/build/services/sub/index.d.ts +18 -0
- package/build/services/sub/index.js +9 -0
- package/build/services/task/index.d.ts +18 -0
- package/build/services/task/index.js +73 -0
- package/build/services/telemetry/index.d.ts +49 -0
- package/build/services/telemetry/index.js +223 -0
- package/build/services/worker/index.d.ts +30 -0
- package/build/services/worker/index.js +105 -0
- package/build/types/activity.d.ts +86 -0
- package/build/types/activity.js +2 -0
- package/build/types/app.d.ts +16 -0
- package/build/types/app.js +2 -0
- package/build/types/async.d.ts +5 -0
- package/build/types/async.js +2 -0
- package/build/types/cache.d.ts +1 -0
- package/build/types/cache.js +2 -0
- package/build/types/collator.d.ts +8 -0
- package/build/types/collator.js +11 -0
- package/build/types/durable.d.ts +59 -0
- package/build/types/durable.js +2 -0
- package/build/types/hook.d.ts +31 -0
- package/build/types/hook.js +9 -0
- package/build/types/hotmesh.d.ts +82 -0
- package/build/types/hotmesh.js +2 -0
- package/build/types/index.d.ts +20 -0
- package/build/types/index.js +21 -0
- package/build/types/ioredisclient.d.ts +5 -0
- package/build/types/ioredisclient.js +5 -0
- package/build/types/job.d.ts +50 -0
- package/build/types/job.js +2 -0
- package/build/types/logger.d.ts +6 -0
- package/build/types/logger.js +2 -0
- package/build/types/map.d.ts +4 -0
- package/build/types/map.js +2 -0
- package/build/types/pipe.d.ts +4 -0
- package/build/types/pipe.js +2 -0
- package/build/types/quorum.d.ts +46 -0
- package/build/types/quorum.js +2 -0
- package/build/types/redis.d.ts +8 -0
- package/build/types/redis.js +2 -0
- package/build/types/redisclient.d.ts +25 -0
- package/build/types/redisclient.js +2 -0
- package/build/types/serializer.d.ts +33 -0
- package/build/types/serializer.js +2 -0
- package/build/types/stats.d.ts +83 -0
- package/build/types/stats.js +2 -0
- package/build/types/stream.d.ts +67 -0
- package/build/types/stream.js +25 -0
- package/build/types/telemetry.d.ts +1 -0
- package/build/types/telemetry.js +11 -0
- package/build/types/transition.d.ts +17 -0
- package/build/types/transition.js +2 -0
- package/index.ts +5 -0
- package/modules/errors.ts +55 -0
- package/modules/key.ts +129 -0
- package/modules/utils.ts +170 -0
- package/package.json +73 -0
- package/services/activities/activity.ts +473 -0
- package/services/activities/await.ts +172 -0
- package/services/activities/emit.ts +25 -0
- package/services/activities/index.ts +15 -0
- package/services/activities/iterate.ts +26 -0
- package/services/activities/trigger.ts +196 -0
- package/services/activities/worker.ts +190 -0
- package/services/collator/README.md +102 -0
- package/services/collator/index.ts +182 -0
- package/services/compiler/deployer.ts +432 -0
- package/services/compiler/index.ts +98 -0
- package/services/compiler/validator.ts +154 -0
- package/services/connector/clients/ioredis.ts +57 -0
- package/services/connector/clients/redis.ts +72 -0
- package/services/connector/index.ts +44 -0
- package/services/dimension/README.md +73 -0
- package/services/dimension/index.ts +39 -0
- package/services/durable/asyncLocalStorage.ts +3 -0
- package/services/durable/client.ts +116 -0
- package/services/durable/connection.ts +50 -0
- package/services/durable/factory.ts +124 -0
- package/services/durable/handle.ts +43 -0
- package/services/durable/index.ts +60 -0
- package/services/durable/native.ts +46 -0
- package/services/durable/worker.ts +254 -0
- package/services/durable/workflow.ts +136 -0
- package/services/engine/index.ts +615 -0
- package/services/hotmesh/index.ts +182 -0
- package/services/logger/index.ts +79 -0
- package/services/mapper/index.ts +84 -0
- package/services/pipe/functions/array.ts +87 -0
- package/services/pipe/functions/bitwise.ts +27 -0
- package/services/pipe/functions/conditional.ts +31 -0
- package/services/pipe/functions/date.ts +214 -0
- package/services/pipe/functions/index.ts +25 -0
- package/services/pipe/functions/json.ts +11 -0
- package/services/pipe/functions/math.ts +143 -0
- package/services/pipe/functions/number.ts +150 -0
- package/services/pipe/functions/object.ts +79 -0
- package/services/pipe/functions/string.ts +86 -0
- package/services/pipe/functions/symbol.ts +39 -0
- package/services/pipe/functions/unary.ts +19 -0
- package/services/pipe/index.ts +138 -0
- package/services/quorum/index.ts +200 -0
- package/services/reporter/index.ts +379 -0
- package/services/serializer/README.md +10 -0
- package/services/serializer/index.ts +243 -0
- package/services/signaler/store.ts +61 -0
- package/services/signaler/stream.ts +354 -0
- package/services/store/cache.ts +172 -0
- package/services/store/clients/ioredis.ts +123 -0
- package/services/store/clients/redis.ts +169 -0
- package/services/store/index.ts +757 -0
- package/services/stream/clients/ioredis.ts +148 -0
- package/services/stream/clients/redis.ts +144 -0
- package/services/stream/index.ts +57 -0
- package/services/sub/clients/ioredis.ts +83 -0
- package/services/sub/clients/redis.ts +74 -0
- package/services/sub/index.ts +25 -0
- package/services/task/index.ts +86 -0
- package/services/telemetry/index.ts +267 -0
- package/services/worker/index.ts +165 -0
- package/types/activity.ts +115 -0
- package/types/app.ts +20 -0
- package/types/async.ts +7 -0
- package/types/cache.ts +1 -0
- package/types/collator.ts +9 -0
- package/types/durable.ts +81 -0
- package/types/hook.ts +32 -0
- package/types/hotmesh.ts +102 -0
- package/types/index.ts +138 -0
- package/types/ioredisclient.ts +10 -0
- package/types/job.ts +59 -0
- package/types/logger.ts +6 -0
- package/types/map.ts +5 -0
- package/types/ms.d.ts +7 -0
- package/types/pipe.ts +7 -0
- package/types/quorum.ts +59 -0
- package/types/redis.ts +27 -0
- package/types/redisclient.ts +29 -0
- package/types/serializer.ts +38 -0
- package/types/stats.ts +100 -0
- package/types/stream.ts +75 -0
- package/types/telemetry.ts +15 -0
- package/types/transition.ts +20 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import packageJson from '../../package.json';
|
|
2
|
+
import { MapperService } from '../mapper';
|
|
3
|
+
import {
|
|
4
|
+
ActivityMetadata,
|
|
5
|
+
ActivityType,
|
|
6
|
+
Consumes } from '../../types/activity';
|
|
7
|
+
import { JobState } from '../../types/job';
|
|
8
|
+
import {
|
|
9
|
+
StringAnyType,
|
|
10
|
+
StringScalarType,
|
|
11
|
+
StringStringType } from '../../types/serializer';
|
|
12
|
+
import { StreamData, StreamDataType, StreamRole } from '../../types/stream';
|
|
13
|
+
import {
|
|
14
|
+
Span,
|
|
15
|
+
SpanContext,
|
|
16
|
+
SpanKind,
|
|
17
|
+
trace,
|
|
18
|
+
Context,
|
|
19
|
+
context,
|
|
20
|
+
SpanStatusCode } from '../../types/telemetry';
|
|
21
|
+
|
|
22
|
+
class TelemetryService {
|
|
23
|
+
span: Span;
|
|
24
|
+
jobSpan: Span;
|
|
25
|
+
config: ActivityType;
|
|
26
|
+
traceId: string | null;
|
|
27
|
+
spanId: string | null;
|
|
28
|
+
appId: string;
|
|
29
|
+
metadata: ActivityMetadata;
|
|
30
|
+
context: JobState;
|
|
31
|
+
leg = 1;
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
appId: string,
|
|
35
|
+
config?: ActivityType,
|
|
36
|
+
metadata?: ActivityMetadata,
|
|
37
|
+
context?: JobState,
|
|
38
|
+
) {
|
|
39
|
+
this.appId = appId;
|
|
40
|
+
//these are REQUIRED for job and activity spans
|
|
41
|
+
this.config = config;
|
|
42
|
+
this.metadata = metadata;
|
|
43
|
+
this.context = context;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getJobParentSpanId(): string | undefined {
|
|
47
|
+
return this.context.metadata.spn;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getActivityParentSpanId(leg: number): string | undefined {
|
|
51
|
+
if (leg === 1) {
|
|
52
|
+
return this.context[this.config.parent].output?.metadata?.l2s;
|
|
53
|
+
} else {
|
|
54
|
+
return this.context['$self'].output?.metadata?.l1s;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getTraceId(): string | undefined {
|
|
59
|
+
return this.context.metadata.trc;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
startJobSpan(): TelemetryService {
|
|
63
|
+
const spanName = `JOB/${this.appId}/${this.config.subscribes}/1`;
|
|
64
|
+
const traceId = this.getTraceId();
|
|
65
|
+
const spanId = this.getJobParentSpanId();
|
|
66
|
+
const attributes = this.getSpanAttrs(1);
|
|
67
|
+
const span: Span = this.startSpan(traceId, spanId, spanName, attributes);
|
|
68
|
+
this.jobSpan = span;
|
|
69
|
+
this.setTelemetryContext(span, 1);
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
startActivitySpan(leg = this.leg): TelemetryService {
|
|
74
|
+
const spanName = `${this.config.type.toUpperCase()}/${this.appId}/${this.metadata.aid}/${leg}`;
|
|
75
|
+
const traceId = this.getTraceId();
|
|
76
|
+
const spanId = this.getActivityParentSpanId(leg);
|
|
77
|
+
const attributes = this.getSpanAttrs(leg);
|
|
78
|
+
const span: Span = this.startSpan(traceId, spanId, spanName, attributes);
|
|
79
|
+
this.setTelemetryContext(span, leg);
|
|
80
|
+
this.span = span;
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
startStreamSpan(data: StreamData, role: StreamRole): TelemetryService {
|
|
85
|
+
let type: string;
|
|
86
|
+
if (role === StreamRole.SYSTEM) {
|
|
87
|
+
type = 'SYSTEM';
|
|
88
|
+
} else if (role === StreamRole.WORKER) {
|
|
89
|
+
type = 'EXECUTE';
|
|
90
|
+
} else if (data.type === StreamDataType.RESULT || data.type === StreamDataType.RESPONSE) {
|
|
91
|
+
type = 'FANIN';
|
|
92
|
+
} else {
|
|
93
|
+
type = 'FANOUT';
|
|
94
|
+
}
|
|
95
|
+
const topic = data.metadata.topic ? `/${data.metadata.topic}` : '';
|
|
96
|
+
const spanName = `${type}/${this.appId}/${data.metadata.aid}${topic}`;
|
|
97
|
+
const attributes = this.getStreamSpanAttrs(data);
|
|
98
|
+
const span: Span = this.startSpan(data.metadata.trc, data.metadata.spn, spanName, attributes);
|
|
99
|
+
this.span = span;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
startSpan(traceId: string, spanId: string, spanName: string, attributes: StringScalarType): Span {
|
|
104
|
+
this.traceId = traceId;
|
|
105
|
+
this.spanId = spanId;
|
|
106
|
+
const tracer = trace.getTracer(packageJson.name, packageJson.version);
|
|
107
|
+
let parentContext = this.getParentSpanContext();
|
|
108
|
+
const span = tracer.startSpan(
|
|
109
|
+
spanName,
|
|
110
|
+
{ kind: SpanKind.CLIENT, attributes, root: !parentContext },
|
|
111
|
+
parentContext
|
|
112
|
+
);
|
|
113
|
+
return span;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
mapActivityAttributes(): void {
|
|
117
|
+
//export user-defined span attributes (app.activity.data.*)
|
|
118
|
+
if (this.config.telemetry) {
|
|
119
|
+
const telemetryAtts = new MapperService(this.config.telemetry, this.context).mapRules();
|
|
120
|
+
const namespacedAtts = {
|
|
121
|
+
...Object.keys(telemetryAtts).reduce((result, key) => {
|
|
122
|
+
if (['string', 'boolean', 'number'].includes(typeof telemetryAtts[key])) {
|
|
123
|
+
result[`app.activity.data.${key}`] = telemetryAtts[key];
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
126
|
+
}, {})
|
|
127
|
+
};
|
|
128
|
+
this.span.setAttributes(namespacedAtts as StringScalarType);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
setActivityAttributes(attributes: StringScalarType): void {
|
|
133
|
+
this.span.setAttributes(attributes);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
setStreamAttributes(attributes: StringScalarType): void {
|
|
137
|
+
this.span.setAttributes(attributes);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
setJobAttributes(attributes: StringScalarType): void {
|
|
141
|
+
this.jobSpan.setAttributes(attributes);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
endJobSpan(): void {
|
|
145
|
+
this.endSpan(this.jobSpan);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
endActivitySpan(): void {
|
|
149
|
+
this.endSpan(this.span);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
endStreamSpan(): void {
|
|
153
|
+
this.endSpan(this.span);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
endSpan(span: Span): void {
|
|
157
|
+
span && span.end();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
getParentSpanContext(): undefined | Context {
|
|
161
|
+
if (this.traceId && this.spanId) {
|
|
162
|
+
const restoredSpanContext: SpanContext = {
|
|
163
|
+
traceId: this.traceId,
|
|
164
|
+
spanId: this.spanId,
|
|
165
|
+
isRemote: true,
|
|
166
|
+
traceFlags: 1, // (todo: revisit sampling strategy/config)
|
|
167
|
+
};
|
|
168
|
+
const parentContext = trace.setSpanContext(context.active(), restoredSpanContext);
|
|
169
|
+
return parentContext;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getSpanAttrs(leg: number): StringAnyType {
|
|
174
|
+
return {
|
|
175
|
+
...Object.keys(this.context.metadata).reduce((result, key) => {
|
|
176
|
+
if (key !== 'trc') {
|
|
177
|
+
result[`app.job.${key}`] = this.context.metadata[key];
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}, {}),
|
|
181
|
+
...Object.keys(this.metadata).reduce((result, key) => {
|
|
182
|
+
result[`app.activity.${key}`] = this.metadata[key];
|
|
183
|
+
return result;
|
|
184
|
+
}, {}),
|
|
185
|
+
'app.activity.leg': leg,
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
getStreamSpanAttrs(input: StreamData): StringAnyType {
|
|
190
|
+
return {
|
|
191
|
+
...Object.keys(input.metadata).reduce((result, key) => {
|
|
192
|
+
if (key !== 'trc' && key !== 'spn') {
|
|
193
|
+
result[`app.stream.${key}`] = input.metadata[key];
|
|
194
|
+
}
|
|
195
|
+
return result;
|
|
196
|
+
}, {})
|
|
197
|
+
};
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
setTelemetryContext(span: Span, leg: number) {
|
|
201
|
+
if (!this.context.metadata.trc) {
|
|
202
|
+
this.context.metadata.trc = span.spanContext().traceId;
|
|
203
|
+
}
|
|
204
|
+
if (leg === 1) {
|
|
205
|
+
if (!this.context['$self'].output.metadata) {
|
|
206
|
+
this.context['$self'].output.metadata = {};
|
|
207
|
+
}
|
|
208
|
+
this.context['$self'].output.metadata.l1s = span.spanContext().spanId;
|
|
209
|
+
} else {
|
|
210
|
+
if (!this.context['$self'].output.metadata) {
|
|
211
|
+
this.context['$self'].output.metadata = {};
|
|
212
|
+
}
|
|
213
|
+
this.context['$self'].output.metadata.l2s = span.spanContext().spanId;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
setActivityError(message: string) {
|
|
218
|
+
this.span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
setStreamError(message: string) {
|
|
222
|
+
this.span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Adds the paths (HGET) necessary to restore telemetry state for an activity
|
|
227
|
+
* @param consumes
|
|
228
|
+
* @param config
|
|
229
|
+
* @param metadata
|
|
230
|
+
* @param leg
|
|
231
|
+
*/
|
|
232
|
+
static addTargetTelemetryPaths(consumes: Consumes, config: ActivityType, metadata: ActivityMetadata, leg: number): void {
|
|
233
|
+
if (leg === 1) {
|
|
234
|
+
if (!(config.parent in consumes)) {
|
|
235
|
+
consumes[config.parent] = [];
|
|
236
|
+
}
|
|
237
|
+
consumes[config.parent].push(`${config.parent}/output/metadata/l2s`);
|
|
238
|
+
} else {
|
|
239
|
+
if (!(metadata.aid in consumes)) {
|
|
240
|
+
consumes[metadata.aid] = [];
|
|
241
|
+
}
|
|
242
|
+
consumes[metadata.aid].push(`${metadata.aid}/output/metadata/l1s`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static bindJobTelemetryToState(state: StringStringType, config: ActivityType, context:JobState) {
|
|
247
|
+
if (config.type === 'trigger') {
|
|
248
|
+
state['metadata/trc'] = context.metadata.trc;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
static bindActivityTelemetryToState(state: StringAnyType, config: ActivityType, metadata: ActivityMetadata, context: JobState, leg: number): void {
|
|
253
|
+
if (config.type === 'trigger') {
|
|
254
|
+
state[`${metadata.aid}/output/metadata/l1s`] = context['$self'].output.metadata.l1s;
|
|
255
|
+
state[`${metadata.aid}/output/metadata/l2s`] = context['$self'].output.metadata.l2s;
|
|
256
|
+
} else if (config.type === 'activity' && leg === 1) {
|
|
257
|
+
//activities run non-duplexed and only have a single leg
|
|
258
|
+
state[`${metadata.aid}/output/metadata/l1s`] = context['$self'].output.metadata.l1s;
|
|
259
|
+
state[`${metadata.aid}/output/metadata/l2s`] = context['$self'].output.metadata.l1s;
|
|
260
|
+
} else {
|
|
261
|
+
const target = `l${leg}s`;
|
|
262
|
+
state[`${metadata.aid}/output/metadata/${target}`] = context['$self'].output.metadata[target];
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export { TelemetryService };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { KeyType } from "../../modules/key";
|
|
2
|
+
import { ILogger } from "../logger";
|
|
3
|
+
import { StreamSignaler } from "../signaler/stream";
|
|
4
|
+
import { StoreService } from '../store';
|
|
5
|
+
import { RedisStoreService as RedisStore } from '../store/clients/redis';
|
|
6
|
+
import { IORedisStoreService as IORedisStore } from '../store/clients/ioredis';
|
|
7
|
+
import { StreamService } from '../stream';
|
|
8
|
+
import { RedisStreamService as RedisStream } from '../stream/clients/redis';
|
|
9
|
+
import { IORedisStreamService as IORedisStream } from '../stream/clients/ioredis';
|
|
10
|
+
import { SubService } from '../sub';
|
|
11
|
+
import { IORedisSubService as IORedisSub } from '../sub/clients/ioredis';
|
|
12
|
+
import { RedisSubService as RedisSub } from '../sub/clients/redis';
|
|
13
|
+
import { RedisClientType as IORedisClientType } from '../../types/ioredisclient';
|
|
14
|
+
import { HotMeshConfig, HotMeshWorker } from "../../types/hotmesh";
|
|
15
|
+
import {
|
|
16
|
+
QuorumMessage,
|
|
17
|
+
SubscriptionCallback } from "../../types/quorum";
|
|
18
|
+
import { RedisClient, RedisMulti } from "../../types/redis";
|
|
19
|
+
import { RedisClientType } from '../../types/redisclient';
|
|
20
|
+
import { StreamRole } from "../../types/stream";
|
|
21
|
+
import { identifyRedisType } from "../../modules/utils";
|
|
22
|
+
import { ConnectorService } from "../connector";
|
|
23
|
+
|
|
24
|
+
class WorkerService {
|
|
25
|
+
namespace: string;
|
|
26
|
+
appId: string;
|
|
27
|
+
guid: string;
|
|
28
|
+
topic: string;
|
|
29
|
+
config: HotMeshConfig;
|
|
30
|
+
store: StoreService<RedisClient, RedisMulti> | null;
|
|
31
|
+
stream: StreamService<RedisClient, RedisMulti> | null;
|
|
32
|
+
subscribe: SubService<RedisClient, RedisMulti> | null;
|
|
33
|
+
streamSignaler: StreamSignaler | null;
|
|
34
|
+
logger: ILogger;
|
|
35
|
+
reporting = false;
|
|
36
|
+
|
|
37
|
+
static async init(
|
|
38
|
+
namespace: string,
|
|
39
|
+
appId: string,
|
|
40
|
+
guid: string,
|
|
41
|
+
config: HotMeshConfig,
|
|
42
|
+
logger: ILogger
|
|
43
|
+
): Promise<WorkerService[]> {
|
|
44
|
+
const services: WorkerService[] = [];
|
|
45
|
+
if (Array.isArray(config.workers)) {
|
|
46
|
+
for (const worker of config.workers) {
|
|
47
|
+
|
|
48
|
+
await ConnectorService.initRedisClients(
|
|
49
|
+
worker.redis?.class,
|
|
50
|
+
worker.redis?.options,
|
|
51
|
+
worker,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const service = new WorkerService();
|
|
55
|
+
service.verifyWorkerFields(worker);
|
|
56
|
+
service.namespace = namespace;
|
|
57
|
+
service.appId = appId;
|
|
58
|
+
service.guid = guid;
|
|
59
|
+
service.topic = worker.topic;
|
|
60
|
+
service.config = config;
|
|
61
|
+
service.logger = logger;
|
|
62
|
+
|
|
63
|
+
await service.initStoreChannel(service, worker.store);
|
|
64
|
+
await service.initSubChannel(service, worker.sub);
|
|
65
|
+
await service.subscribe.subscribe(KeyType.QUORUM, service.subscriptionHandler(), appId);
|
|
66
|
+
await service.subscribe.subscribe(KeyType.QUORUM, service.subscriptionHandler(), appId, service.topic);
|
|
67
|
+
await service.subscribe.subscribe(KeyType.QUORUM, service.subscriptionHandler(), appId, service.guid);
|
|
68
|
+
await service.initStreamChannel(service, worker.stream);
|
|
69
|
+
service.streamSignaler = service.initStreamSignaler(worker, logger);
|
|
70
|
+
|
|
71
|
+
const key = service.stream.mintKey(KeyType.STREAMS, { appId: service.appId, topic: worker.topic });
|
|
72
|
+
await service.streamSignaler.consumeMessages(
|
|
73
|
+
key,
|
|
74
|
+
'WORKER',
|
|
75
|
+
service.guid,
|
|
76
|
+
worker.callback
|
|
77
|
+
);
|
|
78
|
+
services.push(service);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return services;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
verifyWorkerFields(worker: HotMeshWorker) {
|
|
85
|
+
if ((!identifyRedisType(worker.store) ||
|
|
86
|
+
!identifyRedisType(worker.stream)||
|
|
87
|
+
!identifyRedisType(worker.sub)) ||
|
|
88
|
+
!(worker.topic && worker.callback)) {
|
|
89
|
+
throw new Error('worker must include `store`, `stream`, and `sub` fields along with a callback function and topic.');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async initStoreChannel(service: WorkerService, store: RedisClient) {
|
|
94
|
+
if (identifyRedisType(store) === 'redis') {
|
|
95
|
+
service.store = new RedisStore(store as RedisClientType);
|
|
96
|
+
} else {
|
|
97
|
+
service.store = new IORedisStore(store as IORedisClientType);
|
|
98
|
+
}
|
|
99
|
+
await service.store.init(
|
|
100
|
+
service.namespace,
|
|
101
|
+
service.appId,
|
|
102
|
+
service.logger
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async initSubChannel(service: WorkerService, sub: RedisClient) {
|
|
107
|
+
if (identifyRedisType(sub) === 'redis') {
|
|
108
|
+
service.subscribe = new RedisSub(sub as RedisClientType);
|
|
109
|
+
} else {
|
|
110
|
+
service.subscribe = new IORedisSub(sub as IORedisClientType);
|
|
111
|
+
}
|
|
112
|
+
await service.subscribe.init(
|
|
113
|
+
service.namespace,
|
|
114
|
+
service.appId,
|
|
115
|
+
service.guid,
|
|
116
|
+
service.logger
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async initStreamChannel(service: WorkerService, stream: RedisClient) {
|
|
121
|
+
if (identifyRedisType(stream) === 'redis') {
|
|
122
|
+
service.stream = new RedisStream(stream as RedisClientType);
|
|
123
|
+
} else {
|
|
124
|
+
service.stream = new IORedisStream(stream as IORedisClientType);
|
|
125
|
+
}
|
|
126
|
+
await service.stream.init(
|
|
127
|
+
service.namespace,
|
|
128
|
+
service.appId,
|
|
129
|
+
service.logger
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
initStreamSignaler(worker: HotMeshWorker, logger: ILogger): StreamSignaler {
|
|
134
|
+
return new StreamSignaler(
|
|
135
|
+
{
|
|
136
|
+
namespace: this.namespace,
|
|
137
|
+
appId: this.appId,
|
|
138
|
+
guid: this.guid,
|
|
139
|
+
role: StreamRole.WORKER,
|
|
140
|
+
topic: worker.topic,
|
|
141
|
+
reclaimDelay: worker.reclaimDelay,
|
|
142
|
+
reclaimCount: worker.reclaimCount,
|
|
143
|
+
},
|
|
144
|
+
this.stream,
|
|
145
|
+
this.store,
|
|
146
|
+
logger,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
subscriptionHandler(): SubscriptionCallback {
|
|
151
|
+
const self = this;
|
|
152
|
+
return async (topic: string, message: QuorumMessage) => {
|
|
153
|
+
self.logger.debug('worker-event-received', { topic, type: message.type });
|
|
154
|
+
if (message.type === 'throttle') {
|
|
155
|
+
self.throttle(message.throttle);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async throttle(delayInMillis: number) {
|
|
161
|
+
this.streamSignaler.setThrottle(delayInMillis);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export { WorkerService };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { MetricTypes } from "./stats";
|
|
2
|
+
import { StreamRetryPolicy } from "./stream";
|
|
3
|
+
|
|
4
|
+
type ActivityExecutionType = 'trigger' | 'await' | 'worker' | 'activity' | 'emit' | 'iterate';
|
|
5
|
+
|
|
6
|
+
type Consumes = Record<string, string[]>;
|
|
7
|
+
|
|
8
|
+
interface BaseActivity {
|
|
9
|
+
title?: string;
|
|
10
|
+
type?: ActivityExecutionType;
|
|
11
|
+
subtype?: string;
|
|
12
|
+
input?: Record<string, any>;
|
|
13
|
+
output?: Record<string, any>;
|
|
14
|
+
settings?: Record<string, any>;
|
|
15
|
+
job?: Record<string, any>;
|
|
16
|
+
hook?: Record<string, any>;
|
|
17
|
+
telemetry?: Record<string, any>;
|
|
18
|
+
sleep?: number; //@pipe /in seconds
|
|
19
|
+
expire?: number; //-1 forever (15 seconds default); todo: make globally configurable
|
|
20
|
+
retry?: StreamRetryPolicy
|
|
21
|
+
collationInt?: number; //compiler
|
|
22
|
+
consumes?: Consumes; //compiler
|
|
23
|
+
PRODUCES?: string[]; //compiler
|
|
24
|
+
produces?: string[]; //compiler
|
|
25
|
+
publishes?: string; //compiler
|
|
26
|
+
subscribes?: string; //compiler
|
|
27
|
+
trigger?: string; //compiler
|
|
28
|
+
parent?: string; //compiler
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface Measure {
|
|
32
|
+
measure: MetricTypes;
|
|
33
|
+
target: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface TriggerActivityStats {
|
|
37
|
+
id?: { [key: string]: unknown } | string;
|
|
38
|
+
key?: { [key: string]: unknown } | string;
|
|
39
|
+
measures?: Measure[]; //what to capture
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface TriggerActivity extends BaseActivity {
|
|
43
|
+
type: 'trigger';
|
|
44
|
+
stats?: TriggerActivityStats;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface AwaitActivity extends BaseActivity {
|
|
48
|
+
type: 'await';
|
|
49
|
+
eventName: string;
|
|
50
|
+
timeout: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface WorkerActivity extends BaseActivity {
|
|
54
|
+
type: 'worker';
|
|
55
|
+
topic: string;
|
|
56
|
+
timeout: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface EmitActivity extends BaseActivity {
|
|
60
|
+
type: 'emit';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface IterateActivity extends BaseActivity {
|
|
64
|
+
type: 'iterate';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type ActivityType = BaseActivity | TriggerActivity | AwaitActivity | WorkerActivity | EmitActivity | IterateActivity;
|
|
68
|
+
|
|
69
|
+
type ActivityData = Record<string, any>;
|
|
70
|
+
type ActivityMetadata = {
|
|
71
|
+
aid: string; //activity_id
|
|
72
|
+
atp: string; //activity_type
|
|
73
|
+
stp: string; //activity_subtype
|
|
74
|
+
ac: string; //GMT created //activity_created
|
|
75
|
+
au: string; //GMT updated //activity_updated
|
|
76
|
+
err?: string; //stringified error json: {message: string, code: number, error?}
|
|
77
|
+
l1s?: string; //open telemetry span context (leg 1)
|
|
78
|
+
l2s?: string; //open telemetry span context (leg 2)
|
|
79
|
+
dad?: string; //dimensional address
|
|
80
|
+
as?: string; //activity status (e.g., 889000001000001)
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
type ActivityContext = {
|
|
84
|
+
data?: ActivityData | null;
|
|
85
|
+
metadata: ActivityMetadata;
|
|
86
|
+
hook?: ActivityData
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
type ActivityDuplex = 1 | 2;
|
|
90
|
+
|
|
91
|
+
type ActivityDataType = {
|
|
92
|
+
data?: Record<string, unknown>;
|
|
93
|
+
metadata?: Record<string, unknown>;
|
|
94
|
+
hook?: Record<string, unknown>;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
type ActivityLeg = 1 | 2;
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
ActivityContext,
|
|
101
|
+
ActivityData,
|
|
102
|
+
ActivityDataType,
|
|
103
|
+
ActivityDuplex,
|
|
104
|
+
ActivityLeg,
|
|
105
|
+
ActivityMetadata,
|
|
106
|
+
ActivityType,
|
|
107
|
+
Consumes,
|
|
108
|
+
TriggerActivityStats,
|
|
109
|
+
AwaitActivity,
|
|
110
|
+
BaseActivity,
|
|
111
|
+
EmitActivity,
|
|
112
|
+
IterateActivity,
|
|
113
|
+
TriggerActivity,
|
|
114
|
+
WorkerActivity
|
|
115
|
+
};
|
package/types/app.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface App {
|
|
2
|
+
name: string;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
type AppVID = {
|
|
8
|
+
version: string;
|
|
9
|
+
id: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type AppTransitions = {
|
|
13
|
+
[key: string]: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type AppSubscriptions = {
|
|
17
|
+
[key: string]: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { App, AppVID, AppTransitions, AppSubscriptions };
|
package/types/async.ts
ADDED
package/types/cache.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type CacheMode = 'nocache' | 'cache';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type CollationStage = 'enter' | 'exit' | 'confirm';
|
|
2
|
+
|
|
3
|
+
export enum CollationFaultType {
|
|
4
|
+
MISSING = 'missing', //`as` uninitialized; leg1 entry not allowed
|
|
5
|
+
DUPLICATE = 'duplicate', //1st digit < 8
|
|
6
|
+
INACTIVE = 'inactive', //3rd digit is 8
|
|
7
|
+
INVALID = 'invalid', //unknown value (corrupt for unknown reasons)
|
|
8
|
+
FORBIDDEN = 'forbidden', //leg 1 not completed; reentry (leg 2) not allowed
|
|
9
|
+
}
|
package/types/durable.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { RedisClass, RedisOptions } from './redis';
|
|
2
|
+
|
|
3
|
+
type WorkflowOptions = {
|
|
4
|
+
taskQueue: string;
|
|
5
|
+
args: any[]; //input arguments to pass in
|
|
6
|
+
workflowId: string; //execution id (the job id)
|
|
7
|
+
workflowName?: string; //the name of the user's workflow function
|
|
8
|
+
workflowTrace?: string;
|
|
9
|
+
workflowSpan?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type ActivityDataType = {
|
|
13
|
+
activityName: string;
|
|
14
|
+
arguments: any[];
|
|
15
|
+
workflowId: string;
|
|
16
|
+
workflowTopic: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type WorkflowDataType = {
|
|
20
|
+
arguments: any[];
|
|
21
|
+
workflowId: string;
|
|
22
|
+
workflowTopic: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type ConnectionConfig = {
|
|
26
|
+
class: RedisClass;
|
|
27
|
+
options: RedisOptions;
|
|
28
|
+
}
|
|
29
|
+
type Connection = ConnectionConfig;
|
|
30
|
+
type NativeConnection = ConnectionConfig;
|
|
31
|
+
|
|
32
|
+
type ClientConfig = {
|
|
33
|
+
connection: Connection;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type Registry = {
|
|
37
|
+
[key: string]: Function
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type WorkerConfig = {
|
|
41
|
+
connection: Connection;
|
|
42
|
+
namespace: string; //`appid` in the YAML (e.g, 'default')
|
|
43
|
+
taskQueue: string; //`subscribes` in the YAML (e.g, 'hello-world')
|
|
44
|
+
workflowsPath: string; //resolved abs path to dyn import()
|
|
45
|
+
activities: { [key: string]: Function }; //vanilla activity exports
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type ContextType = {
|
|
49
|
+
workflowId: string
|
|
50
|
+
workflowTopic: string
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
type FunctionSignature<T> = T extends (...args: infer A) => infer R ? (...args: A) => R : never;
|
|
54
|
+
type ProxyType<ACT> = {
|
|
55
|
+
[K in keyof ACT]: FunctionSignature<ACT[K]>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type ActivityConfig = {
|
|
59
|
+
startToCloseTimeout: string;
|
|
60
|
+
retryPolicy: {
|
|
61
|
+
initialInterval: string;
|
|
62
|
+
maximumAttempts: number;
|
|
63
|
+
backoffCoefficient: number;
|
|
64
|
+
maximumInterval: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export {
|
|
69
|
+
ActivityConfig,
|
|
70
|
+
ActivityDataType,
|
|
71
|
+
ClientConfig,
|
|
72
|
+
ContextType,
|
|
73
|
+
ConnectionConfig,
|
|
74
|
+
Connection,
|
|
75
|
+
NativeConnection,
|
|
76
|
+
ProxyType,
|
|
77
|
+
Registry,
|
|
78
|
+
WorkerConfig,
|
|
79
|
+
WorkflowDataType,
|
|
80
|
+
WorkflowOptions,
|
|
81
|
+
};
|
package/types/hook.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
interface HookCondition {
|
|
3
|
+
expected: string;
|
|
4
|
+
actual: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
enum HookGate {
|
|
8
|
+
AND = 'and',
|
|
9
|
+
OR = 'or',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface HookConditions {
|
|
13
|
+
gate?: HookGate;
|
|
14
|
+
match: HookCondition[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface HookRule {
|
|
18
|
+
to: string;
|
|
19
|
+
conditions: HookConditions;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface HookRules {
|
|
23
|
+
[eventName: string]: HookRule[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type HookSignal = { topic: string, resolved: string, jobId: string};
|
|
27
|
+
|
|
28
|
+
interface HookInterface {
|
|
29
|
+
(topic: string, data: { [key: string]: any, id: string }): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { HookCondition, HookConditions, HookGate, HookInterface, HookRule, HookRules, HookSignal };
|