@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.
Files changed (263) hide show
  1. package/LICENSE +214 -0
  2. package/README.md +241 -0
  3. package/build/index.d.ts +4 -0
  4. package/build/index.js +7 -0
  5. package/build/modules/errors.d.ts +28 -0
  6. package/build/modules/errors.js +50 -0
  7. package/build/modules/key.d.ts +75 -0
  8. package/build/modules/key.js +116 -0
  9. package/build/modules/utils.d.ts +34 -0
  10. package/build/modules/utils.js +173 -0
  11. package/build/package.json +73 -0
  12. package/build/services/activities/activity.d.ts +59 -0
  13. package/build/services/activities/activity.js +396 -0
  14. package/build/services/activities/await.d.ts +16 -0
  15. package/build/services/activities/await.js +143 -0
  16. package/build/services/activities/emit.d.ts +9 -0
  17. package/build/services/activities/emit.js +13 -0
  18. package/build/services/activities/index.d.ts +15 -0
  19. package/build/services/activities/index.js +16 -0
  20. package/build/services/activities/iterate.d.ts +9 -0
  21. package/build/services/activities/iterate.js +13 -0
  22. package/build/services/activities/trigger.d.ts +22 -0
  23. package/build/services/activities/trigger.js +161 -0
  24. package/build/services/activities/worker.d.ts +17 -0
  25. package/build/services/activities/worker.js +164 -0
  26. package/build/services/collator/index.d.ts +54 -0
  27. package/build/services/collator/index.js +171 -0
  28. package/build/services/compiler/deployer.d.ts +35 -0
  29. package/build/services/compiler/deployer.js +412 -0
  30. package/build/services/compiler/index.d.ts +30 -0
  31. package/build/services/compiler/index.js +111 -0
  32. package/build/services/compiler/validator.d.ts +32 -0
  33. package/build/services/compiler/validator.js +134 -0
  34. package/build/services/connector/clients/ioredis.d.ts +13 -0
  35. package/build/services/connector/clients/ioredis.js +50 -0
  36. package/build/services/connector/clients/redis.d.ts +13 -0
  37. package/build/services/connector/clients/redis.js +62 -0
  38. package/build/services/connector/index.d.ts +5 -0
  39. package/build/services/connector/index.js +31 -0
  40. package/build/services/dimension/index.d.ts +29 -0
  41. package/build/services/dimension/index.js +35 -0
  42. package/build/services/durable/asyncLocalStorage.d.ts +3 -0
  43. package/build/services/durable/asyncLocalStorage.js +5 -0
  44. package/build/services/durable/client.d.ts +15 -0
  45. package/build/services/durable/client.js +108 -0
  46. package/build/services/durable/connection.d.ts +4 -0
  47. package/build/services/durable/connection.js +51 -0
  48. package/build/services/durable/factory.d.ts +3 -0
  49. package/build/services/durable/factory.js +123 -0
  50. package/build/services/durable/handle.d.ts +8 -0
  51. package/build/services/durable/handle.js +38 -0
  52. package/build/services/durable/index.d.ts +57 -0
  53. package/build/services/durable/index.js +58 -0
  54. package/build/services/durable/native.d.ts +4 -0
  55. package/build/services/durable/native.js +47 -0
  56. package/build/services/durable/worker.d.ts +36 -0
  57. package/build/services/durable/worker.js +266 -0
  58. package/build/services/durable/workflow.d.ts +6 -0
  59. package/build/services/durable/workflow.js +135 -0
  60. package/build/services/engine/index.d.ts +82 -0
  61. package/build/services/engine/index.js +511 -0
  62. package/build/services/hotmesh/index.d.ts +45 -0
  63. package/build/services/hotmesh/index.js +134 -0
  64. package/build/services/logger/index.d.ts +17 -0
  65. package/build/services/logger/index.js +73 -0
  66. package/build/services/mapper/index.d.ts +24 -0
  67. package/build/services/mapper/index.js +72 -0
  68. package/build/services/pipe/functions/array.d.ts +24 -0
  69. package/build/services/pipe/functions/array.js +69 -0
  70. package/build/services/pipe/functions/bitwise.d.ts +9 -0
  71. package/build/services/pipe/functions/bitwise.js +24 -0
  72. package/build/services/pipe/functions/conditional.d.ts +10 -0
  73. package/build/services/pipe/functions/conditional.js +27 -0
  74. package/build/services/pipe/functions/date.d.ts +57 -0
  75. package/build/services/pipe/functions/date.js +167 -0
  76. package/build/services/pipe/functions/index.d.ts +25 -0
  77. package/build/services/pipe/functions/index.js +26 -0
  78. package/build/services/pipe/functions/json.d.ts +5 -0
  79. package/build/services/pipe/functions/json.js +12 -0
  80. package/build/services/pipe/functions/math.d.ts +38 -0
  81. package/build/services/pipe/functions/math.js +111 -0
  82. package/build/services/pipe/functions/number.d.ts +25 -0
  83. package/build/services/pipe/functions/number.js +133 -0
  84. package/build/services/pipe/functions/object.d.ts +22 -0
  85. package/build/services/pipe/functions/object.js +63 -0
  86. package/build/services/pipe/functions/string.d.ts +23 -0
  87. package/build/services/pipe/functions/string.js +69 -0
  88. package/build/services/pipe/functions/symbol.d.ts +12 -0
  89. package/build/services/pipe/functions/symbol.js +33 -0
  90. package/build/services/pipe/functions/unary.d.ts +7 -0
  91. package/build/services/pipe/functions/unary.js +18 -0
  92. package/build/services/pipe/index.d.ts +30 -0
  93. package/build/services/pipe/index.js +128 -0
  94. package/build/services/quorum/index.d.ts +34 -0
  95. package/build/services/quorum/index.js +147 -0
  96. package/build/services/reporter/index.d.ts +47 -0
  97. package/build/services/reporter/index.js +330 -0
  98. package/build/services/serializer/index.d.ts +36 -0
  99. package/build/services/serializer/index.js +222 -0
  100. package/build/services/signaler/store.d.ts +15 -0
  101. package/build/services/signaler/store.js +53 -0
  102. package/build/services/signaler/stream.d.ts +43 -0
  103. package/build/services/signaler/stream.js +317 -0
  104. package/build/services/store/cache.d.ts +66 -0
  105. package/build/services/store/cache.js +127 -0
  106. package/build/services/store/clients/ioredis.d.ts +27 -0
  107. package/build/services/store/clients/ioredis.js +96 -0
  108. package/build/services/store/clients/redis.d.ts +29 -0
  109. package/build/services/store/clients/redis.js +143 -0
  110. package/build/services/store/index.d.ts +88 -0
  111. package/build/services/store/index.js +657 -0
  112. package/build/services/stream/clients/ioredis.d.ts +23 -0
  113. package/build/services/stream/clients/ioredis.js +115 -0
  114. package/build/services/stream/clients/redis.d.ts +23 -0
  115. package/build/services/stream/clients/redis.js +119 -0
  116. package/build/services/stream/index.d.ts +21 -0
  117. package/build/services/stream/index.js +9 -0
  118. package/build/services/sub/clients/ioredis.d.ts +20 -0
  119. package/build/services/sub/clients/ioredis.js +72 -0
  120. package/build/services/sub/clients/redis.d.ts +20 -0
  121. package/build/services/sub/clients/redis.js +63 -0
  122. package/build/services/sub/index.d.ts +18 -0
  123. package/build/services/sub/index.js +9 -0
  124. package/build/services/task/index.d.ts +18 -0
  125. package/build/services/task/index.js +73 -0
  126. package/build/services/telemetry/index.d.ts +49 -0
  127. package/build/services/telemetry/index.js +223 -0
  128. package/build/services/worker/index.d.ts +30 -0
  129. package/build/services/worker/index.js +105 -0
  130. package/build/types/activity.d.ts +86 -0
  131. package/build/types/activity.js +2 -0
  132. package/build/types/app.d.ts +16 -0
  133. package/build/types/app.js +2 -0
  134. package/build/types/async.d.ts +5 -0
  135. package/build/types/async.js +2 -0
  136. package/build/types/cache.d.ts +1 -0
  137. package/build/types/cache.js +2 -0
  138. package/build/types/collator.d.ts +8 -0
  139. package/build/types/collator.js +11 -0
  140. package/build/types/durable.d.ts +59 -0
  141. package/build/types/durable.js +2 -0
  142. package/build/types/hook.d.ts +31 -0
  143. package/build/types/hook.js +9 -0
  144. package/build/types/hotmesh.d.ts +82 -0
  145. package/build/types/hotmesh.js +2 -0
  146. package/build/types/index.d.ts +20 -0
  147. package/build/types/index.js +21 -0
  148. package/build/types/ioredisclient.d.ts +5 -0
  149. package/build/types/ioredisclient.js +5 -0
  150. package/build/types/job.d.ts +50 -0
  151. package/build/types/job.js +2 -0
  152. package/build/types/logger.d.ts +6 -0
  153. package/build/types/logger.js +2 -0
  154. package/build/types/map.d.ts +4 -0
  155. package/build/types/map.js +2 -0
  156. package/build/types/pipe.d.ts +4 -0
  157. package/build/types/pipe.js +2 -0
  158. package/build/types/quorum.d.ts +46 -0
  159. package/build/types/quorum.js +2 -0
  160. package/build/types/redis.d.ts +8 -0
  161. package/build/types/redis.js +2 -0
  162. package/build/types/redisclient.d.ts +25 -0
  163. package/build/types/redisclient.js +2 -0
  164. package/build/types/serializer.d.ts +33 -0
  165. package/build/types/serializer.js +2 -0
  166. package/build/types/stats.d.ts +83 -0
  167. package/build/types/stats.js +2 -0
  168. package/build/types/stream.d.ts +67 -0
  169. package/build/types/stream.js +25 -0
  170. package/build/types/telemetry.d.ts +1 -0
  171. package/build/types/telemetry.js +11 -0
  172. package/build/types/transition.d.ts +17 -0
  173. package/build/types/transition.js +2 -0
  174. package/index.ts +5 -0
  175. package/modules/errors.ts +55 -0
  176. package/modules/key.ts +129 -0
  177. package/modules/utils.ts +170 -0
  178. package/package.json +73 -0
  179. package/services/activities/activity.ts +473 -0
  180. package/services/activities/await.ts +172 -0
  181. package/services/activities/emit.ts +25 -0
  182. package/services/activities/index.ts +15 -0
  183. package/services/activities/iterate.ts +26 -0
  184. package/services/activities/trigger.ts +196 -0
  185. package/services/activities/worker.ts +190 -0
  186. package/services/collator/README.md +102 -0
  187. package/services/collator/index.ts +182 -0
  188. package/services/compiler/deployer.ts +432 -0
  189. package/services/compiler/index.ts +98 -0
  190. package/services/compiler/validator.ts +154 -0
  191. package/services/connector/clients/ioredis.ts +57 -0
  192. package/services/connector/clients/redis.ts +72 -0
  193. package/services/connector/index.ts +44 -0
  194. package/services/dimension/README.md +73 -0
  195. package/services/dimension/index.ts +39 -0
  196. package/services/durable/asyncLocalStorage.ts +3 -0
  197. package/services/durable/client.ts +116 -0
  198. package/services/durable/connection.ts +50 -0
  199. package/services/durable/factory.ts +124 -0
  200. package/services/durable/handle.ts +43 -0
  201. package/services/durable/index.ts +60 -0
  202. package/services/durable/native.ts +46 -0
  203. package/services/durable/worker.ts +254 -0
  204. package/services/durable/workflow.ts +136 -0
  205. package/services/engine/index.ts +615 -0
  206. package/services/hotmesh/index.ts +182 -0
  207. package/services/logger/index.ts +79 -0
  208. package/services/mapper/index.ts +84 -0
  209. package/services/pipe/functions/array.ts +87 -0
  210. package/services/pipe/functions/bitwise.ts +27 -0
  211. package/services/pipe/functions/conditional.ts +31 -0
  212. package/services/pipe/functions/date.ts +214 -0
  213. package/services/pipe/functions/index.ts +25 -0
  214. package/services/pipe/functions/json.ts +11 -0
  215. package/services/pipe/functions/math.ts +143 -0
  216. package/services/pipe/functions/number.ts +150 -0
  217. package/services/pipe/functions/object.ts +79 -0
  218. package/services/pipe/functions/string.ts +86 -0
  219. package/services/pipe/functions/symbol.ts +39 -0
  220. package/services/pipe/functions/unary.ts +19 -0
  221. package/services/pipe/index.ts +138 -0
  222. package/services/quorum/index.ts +200 -0
  223. package/services/reporter/index.ts +379 -0
  224. package/services/serializer/README.md +10 -0
  225. package/services/serializer/index.ts +243 -0
  226. package/services/signaler/store.ts +61 -0
  227. package/services/signaler/stream.ts +354 -0
  228. package/services/store/cache.ts +172 -0
  229. package/services/store/clients/ioredis.ts +123 -0
  230. package/services/store/clients/redis.ts +169 -0
  231. package/services/store/index.ts +757 -0
  232. package/services/stream/clients/ioredis.ts +148 -0
  233. package/services/stream/clients/redis.ts +144 -0
  234. package/services/stream/index.ts +57 -0
  235. package/services/sub/clients/ioredis.ts +83 -0
  236. package/services/sub/clients/redis.ts +74 -0
  237. package/services/sub/index.ts +25 -0
  238. package/services/task/index.ts +86 -0
  239. package/services/telemetry/index.ts +267 -0
  240. package/services/worker/index.ts +165 -0
  241. package/types/activity.ts +115 -0
  242. package/types/app.ts +20 -0
  243. package/types/async.ts +7 -0
  244. package/types/cache.ts +1 -0
  245. package/types/collator.ts +9 -0
  246. package/types/durable.ts +81 -0
  247. package/types/hook.ts +32 -0
  248. package/types/hotmesh.ts +102 -0
  249. package/types/index.ts +138 -0
  250. package/types/ioredisclient.ts +10 -0
  251. package/types/job.ts +59 -0
  252. package/types/logger.ts +6 -0
  253. package/types/map.ts +5 -0
  254. package/types/ms.d.ts +7 -0
  255. package/types/pipe.ts +7 -0
  256. package/types/quorum.ts +59 -0
  257. package/types/redis.ts +27 -0
  258. package/types/redisclient.ts +29 -0
  259. package/types/serializer.ts +38 -0
  260. package/types/stats.ts +100 -0
  261. package/types/stream.ts +75 -0
  262. package/types/telemetry.ts +15 -0
  263. 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
@@ -0,0 +1,7 @@
1
+
2
+ type AsyncSignal = {
3
+ topic: string,
4
+ jobId: string
5
+ };
6
+
7
+ export { AsyncSignal };
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
+ }
@@ -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 };