@hotmeshio/hotmesh 0.0.55 → 0.0.57

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 (182) hide show
  1. package/README.md +1 -1
  2. package/build/modules/enums.js +1 -10
  3. package/build/modules/key.d.ts +0 -38
  4. package/build/modules/key.js +4 -46
  5. package/build/modules/utils.d.ts +0 -8
  6. package/build/modules/utils.js +0 -14
  7. package/build/package.json +11 -4
  8. package/build/services/activities/activity.d.ts +0 -28
  9. package/build/services/activities/activity.js +1 -46
  10. package/build/services/activities/await.js +0 -4
  11. package/build/services/activities/cycle.d.ts +0 -7
  12. package/build/services/activities/cycle.js +1 -16
  13. package/build/services/activities/hook.d.ts +0 -6
  14. package/build/services/activities/hook.js +2 -12
  15. package/build/services/activities/interrupt.js +0 -8
  16. package/build/services/activities/signal.d.ts +0 -6
  17. package/build/services/activities/signal.js +0 -15
  18. package/build/services/activities/trigger.d.ts +0 -4
  19. package/build/services/activities/trigger.js +1 -7
  20. package/build/services/activities/worker.js +0 -4
  21. package/build/services/collator/index.d.ts +0 -70
  22. package/build/services/collator/index.js +1 -91
  23. package/build/services/compiler/deployer.js +6 -38
  24. package/build/services/compiler/index.d.ts +0 -15
  25. package/build/services/compiler/index.js +0 -20
  26. package/build/services/compiler/validator.d.ts +0 -3
  27. package/build/services/compiler/validator.js +0 -25
  28. package/build/services/connector/clients/ioredis.d.ts +2 -2
  29. package/build/services/connector/clients/ioredis.js +0 -2
  30. package/build/services/connector/clients/redis.d.ts +4 -4
  31. package/build/services/connector/clients/redis.js +1 -3
  32. package/build/services/connector/index.d.ts +1 -1
  33. package/build/services/connector/index.js +0 -2
  34. package/build/services/durable/client.d.ts +1 -26
  35. package/build/services/durable/client.js +0 -56
  36. package/build/services/durable/exporter.d.ts +0 -22
  37. package/build/services/durable/exporter.js +1 -30
  38. package/build/services/durable/handle.d.ts +0 -36
  39. package/build/services/durable/handle.js +0 -46
  40. package/build/services/durable/index.d.ts +0 -4
  41. package/build/services/durable/index.js +0 -4
  42. package/build/services/durable/schemas/factory.d.ts +0 -29
  43. package/build/services/durable/schemas/factory.js +0 -29
  44. package/build/services/durable/search.d.ts +1 -36
  45. package/build/services/durable/search.js +56 -56
  46. package/build/services/durable/worker.js +2 -22
  47. package/build/services/durable/workflow.d.ts +0 -114
  48. package/build/services/durable/workflow.js +1 -141
  49. package/build/services/engine/index.d.ts +1 -6
  50. package/build/services/engine/index.js +1 -43
  51. package/build/services/exporter/index.d.ts +0 -27
  52. package/build/services/exporter/index.js +0 -33
  53. package/build/services/hotmesh/index.d.ts +2 -2
  54. package/build/services/hotmesh/index.js +1 -9
  55. package/build/services/logger/index.js +0 -2
  56. package/build/services/mapper/index.d.ts +0 -14
  57. package/build/services/mapper/index.js +0 -14
  58. package/build/services/pipe/functions/date.d.ts +0 -7
  59. package/build/services/pipe/functions/date.js +0 -7
  60. package/build/services/pipe/functions/math.js +0 -2
  61. package/build/services/pipe/index.d.ts +0 -15
  62. package/build/services/pipe/index.js +2 -23
  63. package/build/services/quorum/index.d.ts +0 -7
  64. package/build/services/quorum/index.js +0 -21
  65. package/build/services/reporter/index.d.ts +0 -5
  66. package/build/services/reporter/index.js +0 -9
  67. package/build/services/router/index.d.ts +0 -9
  68. package/build/services/router/index.js +2 -38
  69. package/build/services/serializer/index.js +7 -26
  70. package/build/services/store/cache.d.ts +0 -18
  71. package/build/services/store/cache.js +0 -18
  72. package/build/services/store/clients/ioredis.d.ts +1 -1
  73. package/build/services/store/clients/ioredis.js +0 -1
  74. package/build/services/store/clients/redis.d.ts +1 -1
  75. package/build/services/store/index.d.ts +0 -55
  76. package/build/services/store/index.js +5 -81
  77. package/build/services/stream/clients/ioredis.d.ts +1 -1
  78. package/build/services/stream/clients/ioredis.js +1 -4
  79. package/build/services/stream/clients/redis.d.ts +1 -1
  80. package/build/services/sub/clients/ioredis.d.ts +1 -1
  81. package/build/services/sub/clients/redis.d.ts +1 -1
  82. package/build/services/task/index.d.ts +0 -9
  83. package/build/services/task/index.js +0 -31
  84. package/build/services/telemetry/index.d.ts +0 -7
  85. package/build/services/telemetry/index.js +1 -13
  86. package/build/services/worker/index.d.ts +0 -4
  87. package/build/services/worker/index.js +2 -6
  88. package/build/types/activity.d.ts +0 -81
  89. package/build/types/durable.d.ts +26 -177
  90. package/build/types/exporter.d.ts +0 -13
  91. package/build/types/hotmesh.d.ts +4 -16
  92. package/build/types/hotmesh.js +0 -3
  93. package/build/types/index.d.ts +4 -6
  94. package/build/types/index.js +4 -3
  95. package/build/types/job.d.ts +1 -86
  96. package/build/types/pipe.d.ts +0 -65
  97. package/build/types/quorum.d.ts +15 -10
  98. package/build/types/redis.d.ts +225 -7
  99. package/build/types/redis.js +9 -0
  100. package/build/types/stream.d.ts +0 -58
  101. package/build/types/stream.js +0 -4
  102. package/package.json +11 -4
  103. package/types/durable.ts +131 -4
  104. package/types/hotmesh.ts +3 -6
  105. package/types/index.ts +23 -10
  106. package/types/job.ts +1 -1
  107. package/types/quorum.ts +22 -0
  108. package/types/redis.ts +267 -18
  109. package/build/types/ioredisclient.d.ts +0 -5
  110. package/build/types/ioredisclient.js +0 -5
  111. package/build/types/redisclient.d.ts +0 -26
  112. package/build/types/redisclient.js +0 -2
  113. package/modules/enums.ts +0 -62
  114. package/modules/errors.ts +0 -280
  115. package/modules/key.ts +0 -101
  116. package/modules/storage.ts +0 -3
  117. package/modules/utils.ts +0 -242
  118. package/services/activities/activity.ts +0 -589
  119. package/services/activities/await.ts +0 -113
  120. package/services/activities/cycle.ts +0 -115
  121. package/services/activities/hook.ts +0 -197
  122. package/services/activities/index.ts +0 -19
  123. package/services/activities/interrupt.ts +0 -172
  124. package/services/activities/signal.ts +0 -148
  125. package/services/activities/trigger.ts +0 -295
  126. package/services/activities/worker.ts +0 -107
  127. package/services/collator/README.md +0 -102
  128. package/services/collator/index.ts +0 -291
  129. package/services/compiler/deployer.ts +0 -504
  130. package/services/compiler/index.ts +0 -98
  131. package/services/compiler/validator.ts +0 -158
  132. package/services/connector/clients/ioredis.ts +0 -57
  133. package/services/connector/clients/redis.ts +0 -72
  134. package/services/connector/index.ts +0 -42
  135. package/services/durable/client.ts +0 -266
  136. package/services/durable/connection.ts +0 -10
  137. package/services/durable/exporter.ts +0 -232
  138. package/services/durable/handle.ts +0 -160
  139. package/services/durable/index.ts +0 -27
  140. package/services/durable/schemas/factory.ts +0 -2358
  141. package/services/durable/search.ts +0 -196
  142. package/services/durable/worker.ts +0 -401
  143. package/services/durable/workflow.ts +0 -557
  144. package/services/engine/index.ts +0 -761
  145. package/services/exporter/index.ts +0 -146
  146. package/services/hotmesh/index.ts +0 -237
  147. package/services/logger/index.ts +0 -79
  148. package/services/mapper/index.ts +0 -89
  149. package/services/pipe/functions/array.ts +0 -78
  150. package/services/pipe/functions/bitwise.ts +0 -27
  151. package/services/pipe/functions/conditional.ts +0 -35
  152. package/services/pipe/functions/date.ts +0 -220
  153. package/services/pipe/functions/index.ts +0 -27
  154. package/services/pipe/functions/json.ts +0 -11
  155. package/services/pipe/functions/logical.ts +0 -11
  156. package/services/pipe/functions/math.ts +0 -217
  157. package/services/pipe/functions/number.ts +0 -75
  158. package/services/pipe/functions/object.ts +0 -98
  159. package/services/pipe/functions/string.ts +0 -86
  160. package/services/pipe/functions/symbol.ts +0 -39
  161. package/services/pipe/functions/unary.ts +0 -19
  162. package/services/pipe/index.ts +0 -216
  163. package/services/quorum/index.ts +0 -319
  164. package/services/reporter/index.ts +0 -387
  165. package/services/router/index.ts +0 -426
  166. package/services/serializer/README.md +0 -10
  167. package/services/serializer/index.ts +0 -285
  168. package/services/store/cache.ts +0 -172
  169. package/services/store/clients/ioredis.ts +0 -145
  170. package/services/store/clients/redis.ts +0 -191
  171. package/services/store/index.ts +0 -1091
  172. package/services/stream/clients/ioredis.ts +0 -157
  173. package/services/stream/clients/redis.ts +0 -158
  174. package/services/stream/index.ts +0 -58
  175. package/services/sub/clients/ioredis.ts +0 -83
  176. package/services/sub/clients/redis.ts +0 -74
  177. package/services/sub/index.ts +0 -25
  178. package/services/task/index.ts +0 -250
  179. package/services/telemetry/index.ts +0 -273
  180. package/services/worker/index.ts +0 -248
  181. package/types/ioredisclient.ts +0 -10
  182. package/types/redisclient.ts +0 -30
@@ -1,250 +0,0 @@
1
- import {
2
- HMSH_EXPIRE_DURATION,
3
- HMSH_FIDELITY_SECONDS,
4
- HMSH_SCOUT_INTERVAL_SECONDS} from '../../modules/enums';
5
- import { XSleepFor, sleepFor } from '../../modules/utils';
6
- import { ILogger } from '../logger';
7
- import { Pipe } from '../pipe';
8
- import { StoreService } from '../store';
9
- import { HookInterface, HookRule, HookSignal } from '../../types/hook';
10
- import { KeyType } from '../../types/hotmesh';
11
- import { JobCompletionOptions, JobState } from '../../types/job';
12
- import { RedisClient, RedisMulti } from '../../types/redis';
13
- import { WorkListTaskType } from '../../types/task';
14
- import { VALSEP, WEBSEP } from '../../modules/key';
15
-
16
- class TaskService {
17
- store: StoreService<RedisClient, RedisMulti>;
18
- logger: ILogger;
19
- cleanupTimeout: NodeJS.Timeout | null = null;
20
- isScout: boolean = false;
21
- errorCount = 0;
22
-
23
- constructor(
24
- store: StoreService<RedisClient, RedisMulti>,
25
- logger: ILogger
26
- ) {
27
- this.logger = logger;
28
- this.store = store;
29
- }
30
-
31
- async processWebHooks(hookEventCallback: HookInterface): Promise<void> {
32
- const workItemKey = await this.store.getActiveTaskQueue();
33
- if (workItemKey) {
34
- const [topic, sourceKey, scrub, ...sdata] = workItemKey.split(WEBSEP);
35
- const data = JSON.parse(sdata.join(WEBSEP));
36
- const destinationKey = `${sourceKey}:processed`;
37
- const jobId = await this.store.processTaskQueue(sourceKey, destinationKey);
38
- if (jobId) {
39
- //todo: don't use 'id', make configurable using hook rule
40
- await hookEventCallback(topic, { ...data, id: jobId });
41
- } else {
42
- await this.store.deleteProcessedTaskQueue(
43
- workItemKey,
44
- sourceKey,
45
- destinationKey,
46
- scrub === 'true'
47
- );
48
- }
49
- setImmediate(() => this.processWebHooks(hookEventCallback));
50
- }
51
- }
52
-
53
- async enqueueWorkItems(keys: string[]): Promise<void> {
54
- await this.store.addTaskQueues(keys);
55
- }
56
-
57
- async registerJobForCleanup(jobId: string, inSeconds = HMSH_EXPIRE_DURATION, options: JobCompletionOptions): Promise<void> {
58
- if (inSeconds > 0) {
59
- await this.store.expireJob(jobId, inSeconds);
60
- const fromNow = Date.now() + (inSeconds * 1000);
61
- const fidelityMS = HMSH_FIDELITY_SECONDS * 1000;
62
- const timeSlot = Math.floor(fromNow / fidelityMS) * fidelityMS;
63
- await this.store.registerDependenciesForCleanup(
64
- jobId,
65
- timeSlot,
66
- options,
67
- );
68
- }
69
- }
70
-
71
- async registerTimeHook(
72
- jobId: string,
73
- gId: string,
74
- activityId: string,
75
- type: WorkListTaskType,
76
- inSeconds = HMSH_FIDELITY_SECONDS,
77
- dad: string,
78
- multi?: RedisMulti,
79
- ): Promise<void> {
80
- const fromNow = Date.now() + (inSeconds * 1000);
81
- const fidelityMS = HMSH_FIDELITY_SECONDS * 1000;
82
- const awakenTimeSlot = Math.floor(fromNow / fidelityMS) * fidelityMS;
83
- await this.store.registerTimeHook(
84
- jobId,
85
- gId,
86
- activityId,
87
- type,
88
- awakenTimeSlot,
89
- dad,
90
- multi,
91
- );
92
- }
93
-
94
- /**
95
- * Should this engine instance play the role of 'scout' on behalf
96
- * of the entire quorum? The scout role is responsible for processing
97
- * task lists on behalf of the collective.
98
- */
99
- async shouldScout() {
100
- const wasScout = this.isScout;
101
- const isScout = wasScout || (this.isScout = await this.store.reserveScoutRole('time'));
102
- if (isScout) {
103
- if (!wasScout) {
104
- setTimeout(() => {
105
- this.isScout = false;
106
- }, HMSH_SCOUT_INTERVAL_SECONDS * 1_000);
107
- }
108
- return true;
109
- }
110
- return false;
111
- }
112
-
113
- /**
114
- * Callback handler that takes an item from a work list and
115
- * processes according to its type
116
- */
117
- async processTimeHooks(timeEventCallback: (jobId: string, gId: string, activityId: string, type: WorkListTaskType) => Promise<void>, listKey?: string): Promise<void> {
118
- if (await this.shouldScout()) {
119
- try {
120
- const workListTask = await this.store.getNextTask(listKey);
121
-
122
- if (Array.isArray(workListTask)) {
123
- const [listKey, target, gId, activityId, type] = workListTask;
124
- if (type === 'child') {
125
- //continue; this child is listed here for convenience, but
126
- // will be expired by an origin ancestor and is listed there
127
- } else if (type === 'delist') {
128
- //delist the signalKey (target)
129
- const key = this.store.mintKey(KeyType.SIGNALS, { appId: this.store.appId });
130
- await this.store.redisClient[this.store.commands.hdel](key, target);
131
- } else {
132
- //awaken/expire/interrupt
133
- await timeEventCallback(target, gId, activityId, type);
134
- }
135
- await sleepFor(0);
136
- this.errorCount = 0;
137
- this.processTimeHooks(timeEventCallback, listKey);
138
- } else if (workListTask) {
139
- //a worklist was just emptied; try again immediately
140
- await sleepFor(0);
141
- this.errorCount = 0;
142
- this.processTimeHooks(timeEventCallback);
143
- } else {
144
- //no worklists exist; sleep before checking
145
- let sleep = XSleepFor(HMSH_FIDELITY_SECONDS * 1000);
146
- this.cleanupTimeout = sleep.timerId;
147
- await sleep.promise;
148
- this.errorCount = 0;
149
- this.processTimeHooks(timeEventCallback);
150
- }
151
- } catch (err) {
152
- //most common reasons: deleted job not found; container stopping; test stopping
153
- //less common: redis/cluster down; retry with fallback (5s max main reassignment)
154
- this.logger.warn('task-process-timehooks-error', err);
155
- await sleepFor(1_000 * this.errorCount++);
156
- if (this.errorCount < 5) {
157
- this.processTimeHooks(timeEventCallback);
158
- }
159
- }
160
- } else {
161
- //didn't get the scout role; try again in 'one-ish' minutes
162
- let sleep = XSleepFor(HMSH_SCOUT_INTERVAL_SECONDS * 1_000 * 2 * Math.random());
163
- this.cleanupTimeout = sleep.timerId;
164
- await sleep.promise;
165
- this.processTimeHooks(timeEventCallback);
166
- }
167
- }
168
-
169
- cancelCleanup() {
170
- if (this.cleanupTimeout !== undefined) {
171
- clearTimeout(this.cleanupTimeout);
172
- this.cleanupTimeout = undefined;
173
- }
174
- }
175
-
176
- async getHookRule(topic: string): Promise<HookRule | undefined> {
177
- const rules = await this.store.getHookRules();
178
- return rules?.[topic]?.[0] as HookRule;
179
- }
180
-
181
- async registerWebHook(topic: string, context: JobState, dad: string, multi?: RedisMulti): Promise<string> {
182
- const hookRule = await this.getHookRule(topic);
183
- if (hookRule) {
184
- const mapExpression = hookRule.conditions.match[0].expected;
185
- const resolved = Pipe.resolve(mapExpression, context);
186
- const jobId = context.metadata.jid;
187
- const gId = context.metadata.gid;
188
- const activityId = hookRule.to;
189
- //composite keys are used to fully describe the task target
190
- const compositeJobKey = [
191
- activityId,
192
- dad,
193
- gId,
194
- jobId
195
- ].join(WEBSEP);
196
-
197
- const hook: HookSignal = {
198
- topic,
199
- resolved,
200
- jobId: compositeJobKey,
201
- }
202
- await this.store.setHookSignal(hook, multi);
203
- return jobId;
204
- } else {
205
- throw new Error('signaler.registerWebHook:error: hook rule not found');
206
- }
207
- }
208
-
209
- async processWebHookSignal(topic: string, data: Record<string, unknown>): Promise<[string, string, string, string] | undefined> {
210
- const hookRule = await this.getHookRule(topic);
211
- if (hookRule) {
212
- //NOTE: both formats are supported by the mapping engine:
213
- // `$self.hook.data` OR `$hook.data`
214
- const context = { $self: { hook: { data }}, $hook: { data }};
215
- const mapExpression = hookRule.conditions.match[0].actual;
216
- const resolved = Pipe.resolve(mapExpression, context);
217
- const hookSignalId = await this.store.getHookSignal(topic, resolved);
218
- if (!hookSignalId) {
219
- //messages can be double-processed; not an issue; return `undefined`
220
- //users can also provide a bogus topic; not an issue; return `undefined`
221
- return undefined;
222
- }
223
- //`aid` is part of composite key, but the hook `topic` is its public interface;
224
- // this means that a new version of the graph can be deployed and the
225
- // topic can be re-mapped to a different activity id. Outside callers
226
- // can adhere to the unchanged contract (calling the same topic),
227
- // while the internal system can be updated in real-time as necessary.
228
- const [_aid, dad, gid, ...jid] = hookSignalId.split(WEBSEP);
229
- return [jid.join(WEBSEP), hookRule.to, dad, gid];
230
- } else {
231
- throw new Error('signal-not-found');
232
- }
233
- }
234
-
235
- async deleteWebHookSignal(topic: string, data: Record<string, unknown>): Promise<number> {
236
- const hookRule = await this.getHookRule(topic);
237
- if (hookRule) {
238
- //NOTE: both formats are supported by the mapping engine:
239
- // `$self.hook.data` OR `$hook.data`
240
- const context = { $self: { hook: { data }}, $hook: { data }};
241
- const mapExpression = hookRule.conditions.match[0].actual;
242
- const resolved = Pipe.resolve(mapExpression, context);
243
- return await this.store.deleteHookSignal(topic, resolved);
244
- } else {
245
- throw new Error('signaler.process:error: hook rule not found');
246
- }
247
- }
248
- }
249
-
250
- export { TaskService };
@@ -1,273 +0,0 @@
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
- import { polyfill } from '../../modules/utils';
22
-
23
- class TelemetryService {
24
- span: Span;
25
- jobSpan: Span;
26
- config: ActivityType;
27
- traceId: string | null;
28
- spanId: string | null;
29
- appId: string;
30
- metadata: ActivityMetadata;
31
- context: JobState;
32
- leg = 1;
33
-
34
- constructor(
35
- appId: string,
36
- config?: ActivityType,
37
- metadata?: ActivityMetadata,
38
- context?: JobState,
39
- ) {
40
- this.appId = appId;
41
- //these are REQUIRED for job and activity spans
42
- this.config = config;
43
- this.metadata = metadata;
44
- this.context = context;
45
- }
46
-
47
- getJobParentSpanId(): string | undefined {
48
- return this.context.metadata.spn;
49
- }
50
-
51
- getActivityParentSpanId(leg: number): string | undefined {
52
- if (leg === 1) {
53
- return this.context[this.config.parent].output?.metadata?.l2s;
54
- } else {
55
- return this.context['$self'].output?.metadata?.l1s;
56
- }
57
- }
58
-
59
- getTraceId(): string | undefined {
60
- return this.context.metadata.trc;
61
- }
62
-
63
- startJobSpan(): TelemetryService {
64
- const spanName = `JOB/${this.appId}/${this.config.subscribes}/1`;
65
- const traceId = this.getTraceId();
66
- const spanId = this.getJobParentSpanId();
67
- const attributes = this.getSpanAttrs(1);
68
- const span: Span = this.startSpan(traceId, spanId, spanName, attributes);
69
- this.jobSpan = span;
70
- this.setTelemetryContext(span, 1);
71
- return this;
72
- }
73
-
74
- startActivitySpan(leg = this.leg): TelemetryService {
75
- const spanName = `${this.config.type.toUpperCase()}/${this.appId}/${this.metadata.aid}/${leg}`;
76
- const traceId = this.getTraceId();
77
- const spanId = this.getActivityParentSpanId(leg);
78
- const attributes = this.getSpanAttrs(leg);
79
- const span: Span = this.startSpan(traceId, spanId, spanName, attributes);
80
- this.setTelemetryContext(span, leg);
81
- this.span = span;
82
- return this;
83
- }
84
-
85
- startStreamSpan(data: StreamData, role: StreamRole): TelemetryService {
86
- let type: string;
87
- if (role === StreamRole.SYSTEM) {
88
- type = 'SYSTEM';
89
- } else if (role === StreamRole.WORKER) {
90
- type = 'EXECUTE';
91
- } else if (data.type === StreamDataType.RESULT || data.type === StreamDataType.RESPONSE) {
92
- type = 'FANIN';
93
- } else {
94
- type = 'FANOUT';
95
- }
96
- const topic = data.metadata.topic ? `/${data.metadata.topic}` : '';
97
- const spanName = `${type}/${this.appId}/${data.metadata.aid}${topic}`;
98
- const attributes = this.getStreamSpanAttrs(data);
99
- const span: Span = this.startSpan(data.metadata.trc, data.metadata.spn, spanName, attributes);
100
- this.span = span;
101
- return this;
102
- }
103
-
104
- startSpan(traceId: string, spanId: string, spanName: string, attributes: StringScalarType): Span {
105
- this.traceId = traceId;
106
- this.spanId = spanId;
107
- const tracer = trace.getTracer(packageJson.name, packageJson.version);
108
- let parentContext = this.getParentSpanContext();
109
- const span = tracer.startSpan(
110
- spanName,
111
- { kind: SpanKind.CLIENT, attributes, root: !parentContext },
112
- parentContext
113
- );
114
- return span;
115
- }
116
-
117
- mapActivityAttributes(): void {
118
- //export user-defined span attributes (app.activity.data.*)
119
- if (this.config.telemetry) {
120
- const telemetryAtts = new MapperService(this.config.telemetry, this.context).mapRules();
121
- const namespacedAtts = {
122
- ...Object.keys(telemetryAtts).reduce((result, key) => {
123
- if (['string', 'boolean', 'number'].includes(typeof telemetryAtts[key])) {
124
- result[`app.activity.data.${key}`] = telemetryAtts[key];
125
- }
126
- return result;
127
- }, {})
128
- };
129
- this.span?.setAttributes(namespacedAtts as StringScalarType);
130
- }
131
- }
132
-
133
- setActivityAttributes(attributes: StringScalarType): void {
134
- this.span?.setAttributes(attributes);
135
- }
136
-
137
- setStreamAttributes(attributes: StringScalarType): void {
138
- this.span?.setAttributes(attributes);
139
- }
140
-
141
- setJobAttributes(attributes: StringScalarType): void {
142
- this.jobSpan?.setAttributes(attributes);
143
- }
144
-
145
- endJobSpan(): void {
146
- this.endSpan(this.jobSpan);
147
- }
148
-
149
- endActivitySpan(): void {
150
- this.endSpan(this.span);
151
- }
152
-
153
- endStreamSpan(): void {
154
- this.endSpan(this.span);
155
- }
156
-
157
- endSpan(span: Span): void {
158
- span && span.end();
159
- }
160
-
161
- getParentSpanContext(): undefined | Context {
162
- if (this.traceId && this.spanId) {
163
- const restoredSpanContext: SpanContext = {
164
- traceId: this.traceId,
165
- spanId: this.spanId,
166
- isRemote: true,
167
- traceFlags: 1, // (todo: revisit sampling strategy/config)
168
- };
169
- const parentContext = trace.setSpanContext(context.active(), restoredSpanContext);
170
- return parentContext;
171
- }
172
- }
173
-
174
- getSpanAttrs(leg: number): StringAnyType {
175
- return {
176
- ...Object.keys(this.context.metadata).reduce((result, key) => {
177
- if (key !== 'trc') {
178
- result[`app.job.${key}`] = this.context.metadata[key];
179
- }
180
- return result;
181
- }, {}),
182
- ...Object.keys(this.metadata).reduce((result, key) => {
183
- result[`app.activity.${key}`] = this.metadata[key];
184
- return result;
185
- }, {}),
186
- 'app.activity.leg': leg,
187
- };
188
- };
189
-
190
- getStreamSpanAttrs(input: StreamData): StringAnyType {
191
- return {
192
- ...Object.keys(input.metadata).reduce((result, key) => {
193
- if (key !== 'trc' && key !== 'spn') {
194
- result[`app.stream.${key}`] = input.metadata[key];
195
- }
196
- return result;
197
- }, {})
198
- };
199
- };
200
-
201
- setTelemetryContext(span: Span, leg: number) {
202
- if (!this.context.metadata.trc) {
203
- this.context.metadata.trc = span.spanContext().traceId;
204
- }
205
- if (leg === 1) {
206
- if (!this.context['$self'].output.metadata) {
207
- this.context['$self'].output.metadata = {};
208
- }
209
- this.context['$self'].output.metadata.l1s = span.spanContext().spanId;
210
- } else {
211
- if (!this.context['$self'].output.metadata) {
212
- this.context['$self'].output.metadata = {};
213
- }
214
- this.context['$self'].output.metadata.l2s = span.spanContext().spanId;
215
- }
216
- }
217
-
218
- setActivityError(message: string) {
219
- this.span?.setStatus({ code: SpanStatusCode.ERROR, message });
220
- }
221
-
222
- setStreamError(message: string) {
223
- this.span?.setStatus({ code: SpanStatusCode.ERROR, message });
224
- }
225
-
226
- /**
227
- * Adds the paths (HGET) necessary to restore telemetry state for an activity
228
- * @param consumes
229
- * @param config
230
- * @param metadata
231
- * @param leg
232
- */
233
- static addTargetTelemetryPaths(consumes: Consumes, config: ActivityType, metadata: ActivityMetadata, leg: number): void {
234
- if (leg === 1) {
235
- if (!(config.parent in consumes)) {
236
- consumes[config.parent] = [];
237
- }
238
- consumes[config.parent].push(`${config.parent}/output/metadata/l2s`);
239
- } else {
240
- if (!(metadata.aid in consumes)) {
241
- consumes[metadata.aid] = [];
242
- }
243
- consumes[metadata.aid].push(`${metadata.aid}/output/metadata/l1s`);
244
- }
245
- }
246
-
247
- static bindJobTelemetryToState(state: StringStringType, config: ActivityType, context:JobState) {
248
- if (config.type === 'trigger') {
249
- state['metadata/trc'] = context.metadata.trc;
250
- }
251
- }
252
-
253
- static bindActivityTelemetryToState(state: StringAnyType, config: ActivityType, metadata: ActivityMetadata, context: JobState, leg: number): void {
254
- if (config.type === 'trigger') {
255
- //trigger activities run non-duplexed and only have a single leg (2)
256
- state[`${metadata.aid}/output/metadata/l1s`] = context['$self'].output.metadata.l1s;
257
- state[`${metadata.aid}/output/metadata/l2s`] = context['$self'].output.metadata.l2s;
258
- } else if (polyfill.resolveActivityType(config.type) === 'hook' && leg === 1) {
259
- //hook activities run non-duplexed and only have a single leg (1)
260
- state[`${metadata.aid}/output/metadata/l1s`] = context['$self'].output.metadata.l1s;
261
- state[`${metadata.aid}/output/metadata/l2s`] = context['$self'].output.metadata.l1s;
262
- } else if (config.type === 'signal' && leg === 1) {
263
- //signal activities run non-duplexed and only have a single leg (1)
264
- state[`${metadata.aid}/output/metadata/l1s`] = context['$self'].output.metadata.l1s;
265
- state[`${metadata.aid}/output/metadata/l2s`] = context['$self'].output.metadata.l1s;
266
- } else {
267
- const target = `l${leg}s`;
268
- state[`${metadata.aid}/output/metadata/${target}`] = context['$self'].output.metadata[target];
269
- }
270
- }
271
- }
272
-
273
- export { TelemetryService };