@hotmeshio/hotmesh 0.0.55 → 0.0.56

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 (181) hide show
  1. package/build/modules/enums.js +1 -10
  2. package/build/modules/key.d.ts +0 -38
  3. package/build/modules/key.js +4 -46
  4. package/build/modules/utils.d.ts +0 -8
  5. package/build/modules/utils.js +0 -14
  6. package/build/package.json +11 -4
  7. package/build/services/activities/activity.d.ts +0 -28
  8. package/build/services/activities/activity.js +1 -46
  9. package/build/services/activities/await.js +0 -4
  10. package/build/services/activities/cycle.d.ts +0 -7
  11. package/build/services/activities/cycle.js +1 -16
  12. package/build/services/activities/hook.d.ts +0 -6
  13. package/build/services/activities/hook.js +2 -12
  14. package/build/services/activities/interrupt.js +0 -8
  15. package/build/services/activities/signal.d.ts +0 -6
  16. package/build/services/activities/signal.js +0 -15
  17. package/build/services/activities/trigger.d.ts +0 -4
  18. package/build/services/activities/trigger.js +1 -7
  19. package/build/services/activities/worker.js +0 -4
  20. package/build/services/collator/index.d.ts +0 -70
  21. package/build/services/collator/index.js +1 -91
  22. package/build/services/compiler/deployer.js +6 -38
  23. package/build/services/compiler/index.d.ts +0 -15
  24. package/build/services/compiler/index.js +0 -20
  25. package/build/services/compiler/validator.d.ts +0 -3
  26. package/build/services/compiler/validator.js +0 -25
  27. package/build/services/connector/clients/ioredis.d.ts +2 -2
  28. package/build/services/connector/clients/ioredis.js +0 -2
  29. package/build/services/connector/clients/redis.d.ts +4 -4
  30. package/build/services/connector/clients/redis.js +1 -3
  31. package/build/services/connector/index.d.ts +1 -1
  32. package/build/services/connector/index.js +0 -2
  33. package/build/services/durable/client.d.ts +1 -26
  34. package/build/services/durable/client.js +0 -56
  35. package/build/services/durable/exporter.d.ts +0 -22
  36. package/build/services/durable/exporter.js +1 -30
  37. package/build/services/durable/handle.d.ts +0 -36
  38. package/build/services/durable/handle.js +0 -46
  39. package/build/services/durable/index.d.ts +0 -4
  40. package/build/services/durable/index.js +0 -4
  41. package/build/services/durable/schemas/factory.d.ts +0 -29
  42. package/build/services/durable/schemas/factory.js +0 -29
  43. package/build/services/durable/search.d.ts +1 -36
  44. package/build/services/durable/search.js +57 -56
  45. package/build/services/durable/worker.js +2 -22
  46. package/build/services/durable/workflow.d.ts +0 -114
  47. package/build/services/durable/workflow.js +1 -141
  48. package/build/services/engine/index.d.ts +1 -6
  49. package/build/services/engine/index.js +1 -43
  50. package/build/services/exporter/index.d.ts +0 -27
  51. package/build/services/exporter/index.js +0 -33
  52. package/build/services/hotmesh/index.d.ts +2 -2
  53. package/build/services/hotmesh/index.js +1 -9
  54. package/build/services/logger/index.js +0 -2
  55. package/build/services/mapper/index.d.ts +0 -14
  56. package/build/services/mapper/index.js +0 -14
  57. package/build/services/pipe/functions/date.d.ts +0 -7
  58. package/build/services/pipe/functions/date.js +0 -7
  59. package/build/services/pipe/functions/math.js +0 -2
  60. package/build/services/pipe/index.d.ts +0 -15
  61. package/build/services/pipe/index.js +2 -23
  62. package/build/services/quorum/index.d.ts +0 -7
  63. package/build/services/quorum/index.js +0 -21
  64. package/build/services/reporter/index.d.ts +0 -5
  65. package/build/services/reporter/index.js +0 -9
  66. package/build/services/router/index.d.ts +0 -9
  67. package/build/services/router/index.js +2 -38
  68. package/build/services/serializer/index.js +7 -26
  69. package/build/services/store/cache.d.ts +0 -18
  70. package/build/services/store/cache.js +0 -18
  71. package/build/services/store/clients/ioredis.d.ts +1 -1
  72. package/build/services/store/clients/ioredis.js +0 -1
  73. package/build/services/store/clients/redis.d.ts +1 -1
  74. package/build/services/store/index.d.ts +0 -55
  75. package/build/services/store/index.js +5 -81
  76. package/build/services/stream/clients/ioredis.d.ts +1 -1
  77. package/build/services/stream/clients/ioredis.js +1 -4
  78. package/build/services/stream/clients/redis.d.ts +1 -1
  79. package/build/services/sub/clients/ioredis.d.ts +1 -1
  80. package/build/services/sub/clients/redis.d.ts +1 -1
  81. package/build/services/task/index.d.ts +0 -9
  82. package/build/services/task/index.js +0 -31
  83. package/build/services/telemetry/index.d.ts +0 -7
  84. package/build/services/telemetry/index.js +1 -13
  85. package/build/services/worker/index.d.ts +0 -4
  86. package/build/services/worker/index.js +2 -6
  87. package/build/types/activity.d.ts +0 -81
  88. package/build/types/durable.d.ts +25 -177
  89. package/build/types/exporter.d.ts +0 -13
  90. package/build/types/hotmesh.d.ts +4 -16
  91. package/build/types/hotmesh.js +0 -3
  92. package/build/types/index.d.ts +4 -6
  93. package/build/types/index.js +4 -3
  94. package/build/types/job.d.ts +1 -86
  95. package/build/types/pipe.d.ts +0 -65
  96. package/build/types/quorum.d.ts +15 -10
  97. package/build/types/redis.d.ts +225 -7
  98. package/build/types/redis.js +9 -0
  99. package/build/types/stream.d.ts +0 -58
  100. package/build/types/stream.js +0 -4
  101. package/package.json +11 -4
  102. package/types/durable.ts +121 -3
  103. package/types/hotmesh.ts +3 -6
  104. package/types/index.ts +23 -10
  105. package/types/job.ts +1 -1
  106. package/types/quorum.ts +22 -0
  107. package/types/redis.ts +267 -18
  108. package/build/types/ioredisclient.d.ts +0 -5
  109. package/build/types/ioredisclient.js +0 -5
  110. package/build/types/redisclient.d.ts +0 -26
  111. package/build/types/redisclient.js +0 -2
  112. package/modules/enums.ts +0 -62
  113. package/modules/errors.ts +0 -280
  114. package/modules/key.ts +0 -101
  115. package/modules/storage.ts +0 -3
  116. package/modules/utils.ts +0 -242
  117. package/services/activities/activity.ts +0 -589
  118. package/services/activities/await.ts +0 -113
  119. package/services/activities/cycle.ts +0 -115
  120. package/services/activities/hook.ts +0 -197
  121. package/services/activities/index.ts +0 -19
  122. package/services/activities/interrupt.ts +0 -172
  123. package/services/activities/signal.ts +0 -148
  124. package/services/activities/trigger.ts +0 -295
  125. package/services/activities/worker.ts +0 -107
  126. package/services/collator/README.md +0 -102
  127. package/services/collator/index.ts +0 -291
  128. package/services/compiler/deployer.ts +0 -504
  129. package/services/compiler/index.ts +0 -98
  130. package/services/compiler/validator.ts +0 -158
  131. package/services/connector/clients/ioredis.ts +0 -57
  132. package/services/connector/clients/redis.ts +0 -72
  133. package/services/connector/index.ts +0 -42
  134. package/services/durable/client.ts +0 -266
  135. package/services/durable/connection.ts +0 -10
  136. package/services/durable/exporter.ts +0 -232
  137. package/services/durable/handle.ts +0 -160
  138. package/services/durable/index.ts +0 -27
  139. package/services/durable/schemas/factory.ts +0 -2358
  140. package/services/durable/search.ts +0 -196
  141. package/services/durable/worker.ts +0 -401
  142. package/services/durable/workflow.ts +0 -557
  143. package/services/engine/index.ts +0 -761
  144. package/services/exporter/index.ts +0 -146
  145. package/services/hotmesh/index.ts +0 -237
  146. package/services/logger/index.ts +0 -79
  147. package/services/mapper/index.ts +0 -89
  148. package/services/pipe/functions/array.ts +0 -78
  149. package/services/pipe/functions/bitwise.ts +0 -27
  150. package/services/pipe/functions/conditional.ts +0 -35
  151. package/services/pipe/functions/date.ts +0 -220
  152. package/services/pipe/functions/index.ts +0 -27
  153. package/services/pipe/functions/json.ts +0 -11
  154. package/services/pipe/functions/logical.ts +0 -11
  155. package/services/pipe/functions/math.ts +0 -217
  156. package/services/pipe/functions/number.ts +0 -75
  157. package/services/pipe/functions/object.ts +0 -98
  158. package/services/pipe/functions/string.ts +0 -86
  159. package/services/pipe/functions/symbol.ts +0 -39
  160. package/services/pipe/functions/unary.ts +0 -19
  161. package/services/pipe/index.ts +0 -216
  162. package/services/quorum/index.ts +0 -319
  163. package/services/reporter/index.ts +0 -387
  164. package/services/router/index.ts +0 -426
  165. package/services/serializer/README.md +0 -10
  166. package/services/serializer/index.ts +0 -285
  167. package/services/store/cache.ts +0 -172
  168. package/services/store/clients/ioredis.ts +0 -145
  169. package/services/store/clients/redis.ts +0 -191
  170. package/services/store/index.ts +0 -1091
  171. package/services/stream/clients/ioredis.ts +0 -157
  172. package/services/stream/clients/redis.ts +0 -158
  173. package/services/stream/index.ts +0 -58
  174. package/services/sub/clients/ioredis.ts +0 -83
  175. package/services/sub/clients/redis.ts +0 -74
  176. package/services/sub/index.ts +0 -25
  177. package/services/task/index.ts +0 -250
  178. package/services/telemetry/index.ts +0 -273
  179. package/services/worker/index.ts +0 -248
  180. package/types/ioredisclient.ts +0 -10
  181. 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 };