@hotmeshio/hotmesh 0.0.52 → 0.0.54

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 (134) hide show
  1. package/README.md +22 -18
  2. package/build/index.d.ts +1 -2
  3. package/build/index.js +1 -3
  4. package/build/modules/enums.d.ts +8 -3
  5. package/build/modules/enums.js +16 -8
  6. package/build/modules/errors.d.ts +58 -20
  7. package/build/modules/errors.js +90 -33
  8. package/build/package.json +7 -2
  9. package/build/services/activities/activity.d.ts +8 -0
  10. package/build/services/activities/activity.js +63 -14
  11. package/build/services/activities/await.js +6 -6
  12. package/build/services/activities/cycle.d.ts +2 -2
  13. package/build/services/activities/cycle.js +5 -5
  14. package/build/services/activities/hook.js +9 -5
  15. package/build/services/activities/interrupt.d.ts +3 -3
  16. package/build/services/activities/interrupt.js +15 -6
  17. package/build/services/activities/signal.d.ts +2 -2
  18. package/build/services/activities/signal.js +4 -4
  19. package/build/services/activities/trigger.d.ts +5 -2
  20. package/build/services/activities/trigger.js +34 -4
  21. package/build/services/activities/worker.js +6 -6
  22. package/build/services/compiler/deployer.js +33 -5
  23. package/build/services/compiler/validator.d.ts +2 -0
  24. package/build/services/compiler/validator.js +5 -1
  25. package/build/services/durable/client.d.ts +7 -1
  26. package/build/services/durable/client.js +57 -38
  27. package/build/services/durable/exporter.d.ts +27 -81
  28. package/build/services/durable/exporter.js +153 -325
  29. package/build/services/durable/handle.d.ts +13 -8
  30. package/build/services/durable/handle.js +61 -48
  31. package/build/services/durable/index.d.ts +0 -2
  32. package/build/services/durable/index.js +0 -2
  33. package/build/services/durable/schemas/factory.d.ts +33 -0
  34. package/build/services/durable/schemas/factory.js +2356 -0
  35. package/build/services/durable/search.js +8 -8
  36. package/build/services/durable/worker.js +117 -25
  37. package/build/services/durable/workflow.d.ts +67 -52
  38. package/build/services/durable/workflow.js +322 -306
  39. package/build/services/engine/index.d.ts +2 -2
  40. package/build/services/engine/index.js +5 -2
  41. package/build/services/exporter/index.d.ts +2 -4
  42. package/build/services/exporter/index.js +4 -5
  43. package/build/services/hotmesh/index.d.ts +2 -2
  44. package/build/services/hotmesh/index.js +2 -2
  45. package/build/services/mapper/index.d.ts +6 -2
  46. package/build/services/mapper/index.js +6 -2
  47. package/build/services/pipe/functions/array.d.ts +2 -10
  48. package/build/services/pipe/functions/array.js +30 -28
  49. package/build/services/pipe/functions/conditional.d.ts +1 -0
  50. package/build/services/pipe/functions/conditional.js +3 -0
  51. package/build/services/pipe/functions/date.d.ts +1 -0
  52. package/build/services/pipe/functions/date.js +4 -0
  53. package/build/services/pipe/functions/index.d.ts +2 -0
  54. package/build/services/pipe/functions/index.js +2 -0
  55. package/build/services/pipe/functions/logical.d.ts +5 -0
  56. package/build/services/pipe/functions/logical.js +12 -0
  57. package/build/services/pipe/functions/object.d.ts +3 -0
  58. package/build/services/pipe/functions/object.js +25 -7
  59. package/build/services/pipe/index.d.ts +20 -3
  60. package/build/services/pipe/index.js +82 -16
  61. package/build/services/router/index.js +14 -3
  62. package/build/services/serializer/index.d.ts +3 -2
  63. package/build/services/serializer/index.js +11 -4
  64. package/build/services/store/clients/ioredis.js +6 -6
  65. package/build/services/store/clients/redis.js +7 -7
  66. package/build/services/store/index.d.ts +2 -0
  67. package/build/services/store/index.js +4 -1
  68. package/build/services/stream/clients/ioredis.js +8 -8
  69. package/build/services/stream/clients/redis.js +1 -1
  70. package/build/types/activity.d.ts +60 -5
  71. package/build/types/durable.d.ts +183 -36
  72. package/build/types/error.d.ts +48 -0
  73. package/build/types/error.js +2 -0
  74. package/build/types/exporter.d.ts +35 -7
  75. package/build/types/index.d.ts +4 -3
  76. package/build/types/job.d.ts +93 -6
  77. package/build/types/pipe.d.ts +81 -3
  78. package/build/types/stream.d.ts +61 -1
  79. package/build/types/stream.js +4 -0
  80. package/index.ts +1 -2
  81. package/modules/enums.ts +16 -8
  82. package/modules/errors.ts +139 -34
  83. package/package.json +7 -2
  84. package/services/activities/activity.ts +63 -14
  85. package/services/activities/await.ts +6 -6
  86. package/services/activities/cycle.ts +7 -6
  87. package/services/activities/hook.ts +12 -5
  88. package/services/activities/interrupt.ts +19 -9
  89. package/services/activities/signal.ts +6 -5
  90. package/services/activities/trigger.ts +43 -6
  91. package/services/activities/worker.ts +7 -7
  92. package/services/compiler/deployer.ts +33 -6
  93. package/services/compiler/validator.ts +7 -3
  94. package/services/durable/client.ts +49 -22
  95. package/services/durable/exporter.ts +162 -349
  96. package/services/durable/handle.ts +66 -53
  97. package/services/durable/index.ts +0 -2
  98. package/services/durable/schemas/factory.ts +2358 -0
  99. package/services/durable/search.ts +8 -8
  100. package/services/durable/worker.ts +128 -29
  101. package/services/durable/workflow.ts +371 -322
  102. package/services/engine/index.ts +8 -3
  103. package/services/exporter/index.ts +10 -12
  104. package/services/hotmesh/index.ts +4 -3
  105. package/services/mapper/index.ts +6 -2
  106. package/services/pipe/functions/array.ts +24 -37
  107. package/services/pipe/functions/conditional.ts +4 -0
  108. package/services/pipe/functions/date.ts +6 -0
  109. package/services/pipe/functions/index.ts +7 -5
  110. package/services/pipe/functions/logical.ts +11 -0
  111. package/services/pipe/functions/object.ts +26 -7
  112. package/services/pipe/index.ts +99 -21
  113. package/services/quorum/index.ts +1 -3
  114. package/services/router/index.ts +14 -3
  115. package/services/serializer/index.ts +12 -5
  116. package/services/store/clients/ioredis.ts +6 -6
  117. package/services/store/clients/redis.ts +7 -7
  118. package/services/store/index.ts +4 -1
  119. package/services/stream/clients/ioredis.ts +8 -8
  120. package/services/stream/clients/redis.ts +1 -1
  121. package/types/activity.ts +87 -15
  122. package/types/durable.ts +263 -75
  123. package/types/error.ts +52 -0
  124. package/types/exporter.ts +43 -9
  125. package/types/index.ts +14 -8
  126. package/types/job.ts +157 -36
  127. package/types/pipe.ts +84 -3
  128. package/types/stream.ts +82 -23
  129. package/build/services/durable/factory.d.ts +0 -17
  130. package/build/services/durable/factory.js +0 -817
  131. package/build/services/durable/meshos.d.ts +0 -127
  132. package/build/services/durable/meshos.js +0 -380
  133. package/services/durable/factory.ts +0 -818
  134. package/services/durable/meshos.ts +0 -441
@@ -6,13 +6,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Pipe = void 0;
7
7
  const functions_1 = __importDefault(require("./functions"));
8
8
  class Pipe {
9
- constructor(rules, jobData) {
9
+ constructor(rules, jobData, context) {
10
10
  this.rules = rules;
11
11
  this.jobData = jobData;
12
+ this.context = context;
12
13
  }
13
14
  isPipeType(currentRow) {
14
15
  return !Array.isArray(currentRow) && '@pipe' in currentRow;
15
16
  }
17
+ isreduceType(currentRow) {
18
+ return !Array.isArray(currentRow) && '@reduce' in currentRow;
19
+ }
16
20
  static isPipeObject(obj) {
17
21
  return typeof obj === 'object' && obj !== null && !Array.isArray(obj) && '@pipe' in obj;
18
22
  }
@@ -30,36 +34,81 @@ class Pipe {
30
34
  * loop through each PipeItem row in this Pipe, resolving and transforming line by line
31
35
  * @returns {any} the result of the pipe
32
36
  */
33
- process() {
34
- let resolved = this.processCells(this.rules[0]);
37
+ process(resolved = null) {
38
+ let index = 0;
39
+ if (!(resolved || this.isPipeType(this.rules[0]) || this.isreduceType(this.rules[0]))) {
40
+ resolved = this.processCells(this.rules[0]); // Add type assertion
41
+ index = 1;
42
+ }
35
43
  const len = this.rules.length;
36
- for (let i = 1; i < len; i++) {
37
- resolved = this.processRow(this.rules[i], resolved, []);
44
+ const subPipeQueue = [];
45
+ for (let i = index; i < len; i++) {
46
+ resolved = this.processRow(this.rules[i], resolved, subPipeQueue);
38
47
  }
39
48
  return resolved[0];
40
49
  }
50
+ /**
51
+ * Transforms iterable `input` into a single value. Vars $output, $item, $key
52
+ * and $input are available. The final statement in the iterator (the reduction)
53
+ * is assumed to be the return value. A default $output object may be provided
54
+ * to the iterator by placing the the second cell of the preceding row. Otherwise,
55
+ * construct the object during first run and ensure it is the first cell of the
56
+ * last row of the iterator, so it is returned as the $output for the next cycle
57
+ * @param {unknown[]} input
58
+ * @returns {unknown}
59
+ * @private
60
+ */
61
+ reduce(input) {
62
+ let resolved = input[1] ?? null;
63
+ if (Array.isArray(input[0])) {
64
+ for (let index = 0; index < input[0].length; index++) {
65
+ this.context = { $input: input[0], $output: resolved, $item: input[0][index], $key: index.toString(), $index: index };
66
+ resolved = this.process([resolved]);
67
+ }
68
+ }
69
+ else {
70
+ let index = -1;
71
+ for (let $key in input[0]) {
72
+ index++;
73
+ this.context = { $input: input[0], $output: resolved, $item: input[0][$key], $key, $index: index };
74
+ resolved = this.process([resolved]);
75
+ }
76
+ }
77
+ return [resolved];
78
+ }
41
79
  processRow(currentRow, resolvedPriorRow, subPipeQueue) {
42
- if (this.isPipeType(currentRow)) {
43
- //currentRow is a recursive subPipe
44
- const subPipe = new Pipe(currentRow['@pipe'], this.jobData);
80
+ if (resolvedPriorRow && this.isreduceType(currentRow)) {
81
+ //reduce the resolvedPriorRow and return the output from the reducer
82
+ const subPipe = new Pipe(currentRow['@reduce'], this.jobData);
83
+ const reduced = subPipe.reduce(resolvedPriorRow);
84
+ return reduced;
85
+ }
86
+ else if (this.isPipeType(currentRow)) {
87
+ //process subPipe and push to subPipeQueue; echo resolvedPriorRow
88
+ const subPipe = new Pipe(currentRow['@pipe'], this.jobData, this.context);
45
89
  subPipeQueue.push(subPipe.process());
46
- //return prior row as if nothing happened
47
90
  return resolvedPriorRow;
48
91
  }
49
92
  else {
93
+ //pivot the subPipeQueue into the arguments array (resolvedPriorRow)
50
94
  if (subPipeQueue.length > 0) {
51
- //if items in subPipeQueue, flush and use as resolvedPriorRow
52
95
  resolvedPriorRow = [...subPipeQueue];
53
96
  subPipeQueue.length = 0;
54
97
  }
55
- else if (!resolvedPriorRow) {
98
+ if (!resolvedPriorRow) {
56
99
  //if no prior row, use current row as prior row
57
- return [].concat(this.processCells([...currentRow]));
100
+ return [].concat(this.processCells(Array.isArray(currentRow) ? [...currentRow] : []));
58
101
  }
59
102
  else {
60
- const [functionName, ...params] = currentRow;
103
+ const [functionName, ...params] = currentRow; // Add type assertion
61
104
  //use resolved values from prior row (n - 1) as input params to cell 1 function
62
- const resolvedValue = Pipe.resolveFunction(functionName)(...resolvedPriorRow);
105
+ let resolvedValue;
106
+ if (this.isContextVariable(functionName)) {
107
+ resolvedValue = this.resolveContextValue(functionName);
108
+ }
109
+ else {
110
+ resolvedValue = Pipe.resolveFunction(functionName)(...resolvedPriorRow);
111
+ }
63
112
  //resolve remaining cells in row and return concatenated with resolvedValue
64
113
  return [resolvedValue].concat(this.processCells([...params]));
65
114
  }
@@ -80,14 +129,21 @@ class Pipe {
80
129
  }
81
130
  processCells(cells) {
82
131
  const resolved = [];
83
- for (const currentCell of cells) {
84
- resolved.push(this.resolveCellValue(currentCell));
132
+ if (Array.isArray(cells)) {
133
+ for (const currentCell of cells) {
134
+ resolved.push(this.resolveCellValue(currentCell));
135
+ }
85
136
  }
86
137
  return resolved;
87
138
  }
88
139
  isFunction(currentCell) {
89
140
  return typeof currentCell === 'string' && currentCell.startsWith('{@') && currentCell.endsWith('}');
90
141
  }
142
+ isContextVariable(currentCell) {
143
+ if (typeof currentCell === 'string' && currentCell.endsWith('}')) {
144
+ return currentCell.startsWith('{$item') || currentCell.startsWith('{$key') || currentCell.startsWith('{$index') || currentCell.startsWith('{$input') || currentCell.startsWith('{$output');
145
+ }
146
+ }
91
147
  isMappable(currentCell) {
92
148
  return typeof currentCell === 'string' && currentCell.startsWith('{') && currentCell.endsWith('}');
93
149
  }
@@ -96,6 +152,9 @@ class Pipe {
96
152
  const fn = Pipe.resolveFunction(currentCell);
97
153
  return fn.call();
98
154
  }
155
+ else if (this.isContextVariable(currentCell)) {
156
+ return this.resolveContextValue(currentCell);
157
+ }
99
158
  else if (this.isMappable(currentCell)) {
100
159
  return this.resolveMappableValue(currentCell);
101
160
  }
@@ -118,6 +177,13 @@ class Pipe {
118
177
  const term = this.resolveMapTerm(currentCell);
119
178
  return this.getNestedProperty(this.jobData, term);
120
179
  }
180
+ resolveContextValue(currentCell) {
181
+ const term = this.resolveContextTerm(currentCell);
182
+ return this.getNestedProperty(this.context, term);
183
+ }
184
+ resolveContextTerm(currentCell) {
185
+ return currentCell.substring(1, currentCell.length - 1);
186
+ }
121
187
  resolveFunctionTerm(currentCell) {
122
188
  return currentCell.substring(2, currentCell.length - 1);
123
189
  }
@@ -154,7 +154,7 @@ class Router {
154
154
  output = await callback(input);
155
155
  }
156
156
  catch (error) {
157
- this.logger.error(`stream-call-function-error`, { error });
157
+ this.logger.error(`stream-call-function-error`, { ...error, input: input, stack: error.stack, message: error.message, name: error.name, stream, id });
158
158
  output = this.structureUnhandledError(input, error);
159
159
  }
160
160
  return output;
@@ -193,10 +193,19 @@ class Router {
193
193
  }
194
194
  }
195
195
  shouldRetry(input, output) {
196
+ //const isUnhandledEngineError = output.code === 500;
196
197
  const policies = input.policies?.retry;
197
198
  const errorCode = output.code.toString();
198
199
  const policy = policies?.[errorCode];
199
200
  const maxRetries = policy?.[0];
201
+ // if (isUnhandledEngineError && !policy) {
202
+ // //if main goes down, replicas take over within 5s
203
+ // //if this is not system/platform related, the exponential
204
+ // //backoff will be applied and eventually slow to a crawl while
205
+ // //the root cause is identified
206
+ // input.policies = { retry: { [errorCode]: [10] } };
207
+ // return [true, 0];
208
+ // }
200
209
  const tryCount = Math.min(input.metadata.try || 0, enums_1.HMSH_MAX_RETRIES);
201
210
  //only possible values for maxRetries are 1, 2, 3
202
211
  //only possible values for tryCount are 0, 1, 2
@@ -245,13 +254,15 @@ class Router {
245
254
  const message = output.data?.message ? output.data?.message.toString() : enums_1.HMSH_STATUS_UNKNOWN;
246
255
  const statusCode = output.code || output.data?.code;
247
256
  const code = isNaN(statusCode) ? enums_1.HMSH_CODE_UNKNOWN : parseInt(statusCode.toString());
248
- const data = { message, code };
257
+ const stack = output.data?.stack ? output.data?.stack.toString() : undefined;
258
+ const data = { message, code, stack };
249
259
  if (typeof output.data?.error === 'object') {
250
260
  data.error = { ...output.data.error };
251
261
  }
252
262
  return {
253
263
  status: stream_1.StreamStatus.ERROR,
254
264
  code,
265
+ stack,
255
266
  metadata: { ...input.metadata, guid: (0, utils_1.guid)() },
256
267
  data
257
268
  };
@@ -314,7 +325,7 @@ class Router {
314
325
  //The stream activity was not processed within established limits. Possibilities Include:
315
326
  // 1) user error: the workers were not properly configured and are timing out
316
327
  // 2a) system error: JSON is corrupt
317
- // i) bad/unwitting actor
328
+ // i) unwitting actor
318
329
  // ii) corrupt hardware/network/transport/etc
319
330
  // 3b) system error: Redis unable to accept `xadd` request
320
331
  // 4c) system error: Redis unable to accept `xdel`/`xack` request
@@ -30,11 +30,12 @@ export declare class SerializerService {
30
30
  getReverseValueMap(valueMap: SymbolMap): SymbolMap;
31
31
  static filterSymVals(startIndex: number, maxIndex: number, existingSymbolValues: Symbols, proposedValues: Set<string>): Symbols;
32
32
  compress(document: StringStringType, ids: string[]): StringStringType;
33
+ isLiteralKeyType(key: string): boolean;
33
34
  decompress(document: StringStringType, ids: string[]): StringStringType;
34
35
  stringify(document: Record<string, any>): StringStringType;
35
36
  parse(document: StringStringType): any;
36
- toString(value: any): string | undefined;
37
- fromString(value: string | undefined): any;
37
+ static toString(value: any): string | undefined;
38
+ static fromString(value: string | undefined): any;
38
39
  package(multiDimensionalDocument: StringAnyType, ids: string[]): StringStringType;
39
40
  unpackage(document: StringStringType, ids: string[]): StringAnyType;
40
41
  export(): SymbolSets;
@@ -117,6 +117,10 @@ class SerializerService {
117
117
  const shortDimensionalKey = `${shortKey}${dimensionalIndex}`;
118
118
  result[shortDimensionalKey] = source[key];
119
119
  }
120
+ else if (!(key in result) && this.isLiteralKeyType(key)) {
121
+ //mark (-) and search (_)
122
+ result[key] = source[key];
123
+ }
120
124
  }
121
125
  };
122
126
  for (let id of ids) {
@@ -127,6 +131,9 @@ class SerializerService {
127
131
  }
128
132
  return result;
129
133
  }
134
+ isLiteralKeyType(key) {
135
+ return key.startsWith('-') || key.startsWith('_');
136
+ }
130
137
  decompress(document, ids) {
131
138
  if (this.symKeys.size === 0) {
132
139
  return document;
@@ -156,7 +163,7 @@ class SerializerService {
156
163
  stringify(document) {
157
164
  let result = {};
158
165
  for (let key in document) {
159
- let value = this.toString(document[key]);
166
+ let value = SerializerService.toString(document[key]);
160
167
  if (value) {
161
168
  if (/^:*[a-zA-Z]{2}$/.test(value)) {
162
169
  value = ':' + value;
@@ -182,12 +189,12 @@ class SerializerService {
182
189
  if (value?.length === 2 && this.symValMaps.has(value)) {
183
190
  value = this.symValMaps.get(value);
184
191
  }
185
- result[key] = this.fromString(value);
192
+ result[key] = SerializerService.fromString(value);
186
193
  }
187
194
  }
188
195
  return result;
189
196
  }
190
- toString(value) {
197
+ static toString(value) {
191
198
  switch (typeof value) {
192
199
  case 'string':
193
200
  break;
@@ -210,7 +217,7 @@ class SerializerService {
210
217
  }
211
218
  return value;
212
219
  }
213
- fromString(value) {
220
+ static fromString(value) {
214
221
  if (typeof value !== 'string')
215
222
  return undefined;
216
223
  const prefix = value.slice(0, 2);
@@ -65,7 +65,7 @@ class IORedisStoreService extends index_1.StoreService {
65
65
  return await (multi || this.redisClient).xadd(key, id, messageId, messageValue);
66
66
  }
67
67
  catch (error) {
68
- this.logger.error(`Error publishing 'xadd'; key: ${key}`, { error });
68
+ this.logger.error(`Error publishing 'xadd'; key: ${key}`, { ...error });
69
69
  throw error;
70
70
  }
71
71
  }
@@ -74,7 +74,7 @@ class IORedisStoreService extends index_1.StoreService {
74
74
  return await this.redisClient.xpending(key, group, start, end, count, consumer);
75
75
  }
76
76
  catch (error) {
77
- this.logger.error(`Error in retrieving pending messages for [stream ${key}], [group ${group}]`, { error });
77
+ this.logger.error(`Error in retrieving pending messages for [stream ${key}], [group ${group}]`, { ...error });
78
78
  throw error;
79
79
  }
80
80
  }
@@ -83,7 +83,7 @@ class IORedisStoreService extends index_1.StoreService {
83
83
  return await this.redisClient.xclaim(key, group, consumer, minIdleTime, id, ...args);
84
84
  }
85
85
  catch (error) {
86
- this.logger.error(`Error in claiming message with id: ${id} in group: ${group} for key: ${key}`, { error });
86
+ this.logger.error(`Error in claiming message with id: ${id} in group: ${group} for key: ${key}`, { ...error });
87
87
  throw error;
88
88
  }
89
89
  }
@@ -92,7 +92,7 @@ class IORedisStoreService extends index_1.StoreService {
92
92
  return await (multi || this.redisClient).xack(key, group, id);
93
93
  }
94
94
  catch (error) {
95
- this.logger.error(`Error in acknowledging messages in group: ${group} for key: ${key}`, { error });
95
+ this.logger.error(`Error in acknowledging messages in group: ${group} for key: ${key}`, { ...error });
96
96
  throw error;
97
97
  }
98
98
  }
@@ -101,7 +101,7 @@ class IORedisStoreService extends index_1.StoreService {
101
101
  return await (multi || this.redisClient).xdel(key, id);
102
102
  }
103
103
  catch (error) {
104
- this.logger.error(`Error in deleting messages with id: ${id} for key: ${key}`, { error });
104
+ this.logger.error(`Error in deleting messages with id: ${id} for key: ${key}`, { ...error });
105
105
  throw error;
106
106
  }
107
107
  }
@@ -110,7 +110,7 @@ class IORedisStoreService extends index_1.StoreService {
110
110
  return await (multi || this.redisClient).xlen(key);
111
111
  }
112
112
  catch (error) {
113
- this.logger.error(`Error getting stream depth: ${key}`, { error });
113
+ this.logger.error(`Error getting stream depth: ${key}`, { ...error });
114
114
  throw error;
115
115
  }
116
116
  }
@@ -71,7 +71,7 @@ class RedisStoreService extends index_1.StoreService {
71
71
  }
72
72
  catch (error) {
73
73
  const streamType = mkStream === 'MKSTREAM' ? 'with MKSTREAM' : 'without MKSTREAM';
74
- this.logger.debug(`x-group-error ${streamType} for key: ${key} and group: ${groupName}`, { error });
74
+ this.logger.debug(`x-group-error ${streamType} for key: ${key} and group: ${groupName}`, { ...error });
75
75
  throw error;
76
76
  }
77
77
  }
@@ -84,7 +84,7 @@ class RedisStoreService extends index_1.StoreService {
84
84
  return await (multi || this.redisClient).XADD(key, id, { [args[0]]: args[1] });
85
85
  }
86
86
  catch (error) {
87
- this.logger.error(`Error publishing 'xadd'; key: ${key}`, { error });
87
+ this.logger.error(`Error publishing 'xadd'; key: ${key}`, { ...error });
88
88
  throw error;
89
89
  }
90
90
  }
@@ -102,7 +102,7 @@ class RedisStoreService extends index_1.StoreService {
102
102
  return await this.redisClient.sendCommand(['XPENDING', ...args]);
103
103
  }
104
104
  catch (error) {
105
- this.logger.error(`Error in retrieving pending messages for group: ${group} in key: ${key}`, { error });
105
+ this.logger.error(`Error in retrieving pending messages for group: ${group} in key: ${key}`, { ...error });
106
106
  throw error;
107
107
  }
108
108
  }
@@ -111,7 +111,7 @@ class RedisStoreService extends index_1.StoreService {
111
111
  return await this.redisClient.sendCommand(['XCLAIM', key, group, consumer, minIdleTime.toString(), id, ...args]);
112
112
  }
113
113
  catch (error) {
114
- this.logger.error(`Error in claiming message with id: ${id} in group: ${group} for key: ${key}`, { error });
114
+ this.logger.error(`Error in claiming message with id: ${id} in group: ${group} for key: ${key}`, { ...error });
115
115
  throw error;
116
116
  }
117
117
  }
@@ -126,7 +126,7 @@ class RedisStoreService extends index_1.StoreService {
126
126
  }
127
127
  }
128
128
  catch (error) {
129
- this.logger.error(`Error in acknowledging messages in group: ${group} for key: ${key}`, { error });
129
+ this.logger.error(`Error in acknowledging messages in group: ${group} for key: ${key}`, { ...error });
130
130
  throw error;
131
131
  }
132
132
  }
@@ -141,7 +141,7 @@ class RedisStoreService extends index_1.StoreService {
141
141
  }
142
142
  }
143
143
  catch (error) {
144
- this.logger.error(`Error in deleting messages with ids: ${id} for key: ${key}`, { error });
144
+ this.logger.error(`Error in deleting messages with ids: ${id} for key: ${key}`, { ...error });
145
145
  throw error;
146
146
  }
147
147
  }
@@ -156,7 +156,7 @@ class RedisStoreService extends index_1.StoreService {
156
156
  }
157
157
  }
158
158
  catch (error) {
159
- this.logger.error(`Error getting stream depth: ${key}`, { error });
159
+ this.logger.error(`Error getting stream depth: ${key}`, { ...error });
160
160
  throw error;
161
161
  }
162
162
  }
@@ -149,6 +149,8 @@ declare abstract class StoreService<T, U extends AbstractRedisClient> {
149
149
  * This method is called by the engine and not by an activity and is
150
150
  * followed by a call to execute job completion/cleanup tasks
151
151
  * associated with a job completion event.
152
+ *
153
+ * Todo: move most of this logic to the engine (too much logic for the store)
152
154
  */
153
155
  interrupt(topic: string, jobId: string, options?: JobInterruptOptions): Promise<void>;
154
156
  scrub(jobId: string): Promise<void>;
@@ -850,6 +850,8 @@ class StoreService {
850
850
  * This method is called by the engine and not by an activity and is
851
851
  * followed by a call to execute job completion/cleanup tasks
852
852
  * associated with a job completion event.
853
+ *
854
+ * Todo: move most of this logic to the engine (too much logic for the store)
853
855
  */
854
856
  async interrupt(topic, jobId, options = {}) {
855
857
  try {
@@ -876,8 +878,9 @@ class StoreService {
876
878
  this.serializer.resetSymbols(symKeys, symVals, {});
877
879
  //persists the standard 410 error (job is `gone`)
878
880
  const err = JSON.stringify({
879
- code: enums_1.HMSH_CODE_INTERRUPT,
881
+ code: options.code ?? enums_1.HMSH_CODE_INTERRUPT,
880
882
  message: options.reason ?? `job [${jobId}] interrupted`,
883
+ stack: options.stack ?? '',
881
884
  job_id: jobId
882
885
  });
883
886
  const payload = { [errKey]: amount.toString() };
@@ -45,7 +45,7 @@ class IORedisStreamService extends index_1.StreamService {
45
45
  return await (multi || this.redisClient).xadd(key, id, messageId, messageValue);
46
46
  }
47
47
  catch (error) {
48
- this.logger.error(`Error publishing 'xadd'; key: ${key}`, { error });
48
+ this.logger.error(`Error publishing 'xadd'; key: ${key}`, { ...error });
49
49
  throw error;
50
50
  }
51
51
  }
@@ -57,7 +57,7 @@ class IORedisStreamService extends index_1.StreamService {
57
57
  blockOption, blockTime, streamsOption, streamName, id);
58
58
  }
59
59
  catch (error) {
60
- this.logger.error(`Error reading stream data [Stream ${streamName}] [Group ${groupName}]`, { error });
60
+ this.logger.error(`Error reading stream data [Stream ${streamName}] [Group ${groupName}]`, { ...error });
61
61
  throw error;
62
62
  }
63
63
  }
@@ -76,11 +76,11 @@ class IORedisStreamService extends index_1.StreamService {
76
76
  return await this.redisClient.call('XPENDING', ...args);
77
77
  }
78
78
  catch (error) {
79
- this.logger.error('err, args', { error }, args);
79
+ this.logger.error('err, args', { ...error }, args);
80
80
  }
81
81
  }
82
82
  catch (error) {
83
- this.logger.error(`Error in retrieving pending messages for [stream ${key}], [group ${group}]`, { error });
83
+ this.logger.error(`Error in retrieving pending messages for [stream ${key}], [group ${group}]`, { ...error });
84
84
  throw error;
85
85
  }
86
86
  }
@@ -89,7 +89,7 @@ class IORedisStreamService extends index_1.StreamService {
89
89
  return await this.redisClient.xclaim(key, group, consumer, minIdleTime, id, ...args);
90
90
  }
91
91
  catch (error) {
92
- this.logger.error(`Error in claiming message with id: ${id} in group: ${group} for key: ${key}`, { error });
92
+ this.logger.error(`Error in claiming message with id: ${id} in group: ${group} for key: ${key}`, { ...error });
93
93
  throw error;
94
94
  }
95
95
  }
@@ -98,7 +98,7 @@ class IORedisStreamService extends index_1.StreamService {
98
98
  return await (multi || this.redisClient).xack(key, group, id);
99
99
  }
100
100
  catch (error) {
101
- this.logger.error(`Error in acknowledging messages in group: ${group} for key: ${key}`, { error });
101
+ this.logger.error(`Error in acknowledging messages in group: ${group} for key: ${key}`, { ...error });
102
102
  throw error;
103
103
  }
104
104
  }
@@ -107,7 +107,7 @@ class IORedisStreamService extends index_1.StreamService {
107
107
  return await (multi || this.redisClient).xdel(key, id);
108
108
  }
109
109
  catch (error) {
110
- this.logger.error(`Error in deleting messages with id: ${id} for key: ${key}`, { error });
110
+ this.logger.error(`Error in deleting messages with id: ${id} for key: ${key}`, { ...error });
111
111
  throw error;
112
112
  }
113
113
  }
@@ -116,7 +116,7 @@ class IORedisStreamService extends index_1.StreamService {
116
116
  return await (multi || this.redisClient).xlen(key);
117
117
  }
118
118
  catch (error) {
119
- this.logger.error(`Error getting stream depth: ${key}`, { error });
119
+ this.logger.error(`Error getting stream depth: ${key}`, { ...error });
120
120
  throw error;
121
121
  }
122
122
  }
@@ -126,7 +126,7 @@ class RedisStreamService extends index_1.StreamService {
126
126
  }
127
127
  }
128
128
  catch (error) {
129
- this.logger.error(`Error getting stream depth: ${key}`, { error });
129
+ this.logger.error(`Error getting stream depth: ${key}`, { ...error });
130
130
  throw error;
131
131
  }
132
132
  }
@@ -102,29 +102,84 @@ interface SignalActivity extends BaseActivity {
102
102
  }
103
103
  interface InterruptActivity extends BaseActivity {
104
104
  type: 'interrupt';
105
- /** Optional Reason; will be used as the error `message` when thrown; NOTE: 410 is the error `code` */
105
+ /**
106
+ * Optional Reason; will be used as the error `message` when thrown
107
+ * @default 'Job Interrupted'
108
+ */
106
109
  reason?: string;
107
- /** default is `true` (throw JobInterrupted error upon interrupting) */
110
+ /**
111
+ * throw JobInterrupted error upon interrupting
112
+ * @default true
113
+ */
108
114
  throw?: boolean;
109
- /** TODO: // default is `false` (do not interrupt child jobs) */
115
+ /**
116
+ * Interrupt child/descendant jobs
117
+ * @default false
118
+ */
110
119
  descend?: boolean;
111
- /** target job id (if not present the current job will be targeted) */
120
+ /**
121
+ * Target job id (if not present the current job will be targeted)
122
+ */
112
123
  target?: string;
113
- /** topic to publish the interrupt message (if not present the current job topic will be used) */
124
+ /**
125
+ * Optional topic to publish the interrupt message (if not present the current job topic will be used
126
+ */
114
127
  topic?: string;
128
+ /**
129
+ * Optional Error Code; will be used as the error `code` when thrown
130
+ * @default 410
131
+ */
132
+ code?: number;
133
+ /**
134
+ * Optional stack trace
135
+ */
136
+ stack?: string;
115
137
  }
116
138
  type ActivityType = BaseActivity | TriggerActivity | AwaitActivity | WorkerActivity | InterruptActivity | HookActivity | SignalActivity | CycleActivity;
117
139
  type ActivityData = Record<string, any>;
140
+ /**
141
+ * Type definition for activity metadata.
142
+ */
118
143
  type ActivityMetadata = {
144
+ /**
145
+ * Unique identifier for the activity.
146
+ */
119
147
  aid: string;
148
+ /**
149
+ * Type of the activity.
150
+ */
120
151
  atp: string;
152
+ /**
153
+ * Subtype of the activity.
154
+ */
121
155
  stp: string;
156
+ /**
157
+ * Timestamp when the activity was created, in GMT.
158
+ */
122
159
  ac: string;
160
+ /**
161
+ * Timestamp when the activity was last updated, in GMT.
162
+ */
123
163
  au: string;
164
+ /**
165
+ * Optional stringified JSON containing error details such as message, code, and an optional error object.
166
+ */
124
167
  err?: string;
168
+ /**
169
+ * OpenTelemetry span context for the first leg of the activity.
170
+ */
125
171
  l1s?: string;
172
+ /**
173
+ * OpenTelemetry span context for the second leg of the activity.
174
+ */
126
175
  l2s?: string;
176
+ /**
177
+ * Dimensional address, used for additional metadata.
178
+ */
127
179
  dad?: string;
180
+ /**
181
+ * Status of the activity, could be codes representing different states.
182
+ */
128
183
  as?: string;
129
184
  };
130
185
  type ActivityContext = {