@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.
- package/README.md +22 -18
- package/build/index.d.ts +1 -2
- package/build/index.js +1 -3
- package/build/modules/enums.d.ts +8 -3
- package/build/modules/enums.js +16 -8
- package/build/modules/errors.d.ts +58 -20
- package/build/modules/errors.js +90 -33
- package/build/package.json +7 -2
- package/build/services/activities/activity.d.ts +8 -0
- package/build/services/activities/activity.js +63 -14
- package/build/services/activities/await.js +6 -6
- package/build/services/activities/cycle.d.ts +2 -2
- package/build/services/activities/cycle.js +5 -5
- package/build/services/activities/hook.js +9 -5
- package/build/services/activities/interrupt.d.ts +3 -3
- package/build/services/activities/interrupt.js +15 -6
- package/build/services/activities/signal.d.ts +2 -2
- package/build/services/activities/signal.js +4 -4
- package/build/services/activities/trigger.d.ts +5 -2
- package/build/services/activities/trigger.js +34 -4
- package/build/services/activities/worker.js +6 -6
- package/build/services/compiler/deployer.js +33 -5
- package/build/services/compiler/validator.d.ts +2 -0
- package/build/services/compiler/validator.js +5 -1
- package/build/services/durable/client.d.ts +7 -1
- package/build/services/durable/client.js +57 -38
- package/build/services/durable/exporter.d.ts +27 -81
- package/build/services/durable/exporter.js +153 -325
- package/build/services/durable/handle.d.ts +13 -8
- package/build/services/durable/handle.js +61 -48
- package/build/services/durable/index.d.ts +0 -2
- package/build/services/durable/index.js +0 -2
- package/build/services/durable/schemas/factory.d.ts +33 -0
- package/build/services/durable/schemas/factory.js +2356 -0
- package/build/services/durable/search.js +8 -8
- package/build/services/durable/worker.js +117 -25
- package/build/services/durable/workflow.d.ts +67 -52
- package/build/services/durable/workflow.js +322 -306
- package/build/services/engine/index.d.ts +2 -2
- package/build/services/engine/index.js +5 -2
- package/build/services/exporter/index.d.ts +2 -4
- package/build/services/exporter/index.js +4 -5
- package/build/services/hotmesh/index.d.ts +2 -2
- package/build/services/hotmesh/index.js +2 -2
- package/build/services/mapper/index.d.ts +6 -2
- package/build/services/mapper/index.js +6 -2
- package/build/services/pipe/functions/array.d.ts +2 -10
- package/build/services/pipe/functions/array.js +30 -28
- package/build/services/pipe/functions/conditional.d.ts +1 -0
- package/build/services/pipe/functions/conditional.js +3 -0
- package/build/services/pipe/functions/date.d.ts +1 -0
- package/build/services/pipe/functions/date.js +4 -0
- package/build/services/pipe/functions/index.d.ts +2 -0
- package/build/services/pipe/functions/index.js +2 -0
- package/build/services/pipe/functions/logical.d.ts +5 -0
- package/build/services/pipe/functions/logical.js +12 -0
- package/build/services/pipe/functions/object.d.ts +3 -0
- package/build/services/pipe/functions/object.js +25 -7
- package/build/services/pipe/index.d.ts +20 -3
- package/build/services/pipe/index.js +82 -16
- package/build/services/router/index.js +14 -3
- package/build/services/serializer/index.d.ts +3 -2
- package/build/services/serializer/index.js +11 -4
- package/build/services/store/clients/ioredis.js +6 -6
- package/build/services/store/clients/redis.js +7 -7
- package/build/services/store/index.d.ts +2 -0
- package/build/services/store/index.js +4 -1
- package/build/services/stream/clients/ioredis.js +8 -8
- package/build/services/stream/clients/redis.js +1 -1
- package/build/types/activity.d.ts +60 -5
- package/build/types/durable.d.ts +183 -36
- package/build/types/error.d.ts +48 -0
- package/build/types/error.js +2 -0
- package/build/types/exporter.d.ts +35 -7
- package/build/types/index.d.ts +4 -3
- package/build/types/job.d.ts +93 -6
- package/build/types/pipe.d.ts +81 -3
- package/build/types/stream.d.ts +61 -1
- package/build/types/stream.js +4 -0
- package/index.ts +1 -2
- package/modules/enums.ts +16 -8
- package/modules/errors.ts +139 -34
- package/package.json +7 -2
- package/services/activities/activity.ts +63 -14
- package/services/activities/await.ts +6 -6
- package/services/activities/cycle.ts +7 -6
- package/services/activities/hook.ts +12 -5
- package/services/activities/interrupt.ts +19 -9
- package/services/activities/signal.ts +6 -5
- package/services/activities/trigger.ts +43 -6
- package/services/activities/worker.ts +7 -7
- package/services/compiler/deployer.ts +33 -6
- package/services/compiler/validator.ts +7 -3
- package/services/durable/client.ts +49 -22
- package/services/durable/exporter.ts +162 -349
- package/services/durable/handle.ts +66 -53
- package/services/durable/index.ts +0 -2
- package/services/durable/schemas/factory.ts +2358 -0
- package/services/durable/search.ts +8 -8
- package/services/durable/worker.ts +128 -29
- package/services/durable/workflow.ts +371 -322
- package/services/engine/index.ts +8 -3
- package/services/exporter/index.ts +10 -12
- package/services/hotmesh/index.ts +4 -3
- package/services/mapper/index.ts +6 -2
- package/services/pipe/functions/array.ts +24 -37
- package/services/pipe/functions/conditional.ts +4 -0
- package/services/pipe/functions/date.ts +6 -0
- package/services/pipe/functions/index.ts +7 -5
- package/services/pipe/functions/logical.ts +11 -0
- package/services/pipe/functions/object.ts +26 -7
- package/services/pipe/index.ts +99 -21
- package/services/quorum/index.ts +1 -3
- package/services/router/index.ts +14 -3
- package/services/serializer/index.ts +12 -5
- package/services/store/clients/ioredis.ts +6 -6
- package/services/store/clients/redis.ts +7 -7
- package/services/store/index.ts +4 -1
- package/services/stream/clients/ioredis.ts +8 -8
- package/services/stream/clients/redis.ts +1 -1
- package/types/activity.ts +87 -15
- package/types/durable.ts +263 -75
- package/types/error.ts +52 -0
- package/types/exporter.ts +43 -9
- package/types/index.ts +14 -8
- package/types/job.ts +157 -36
- package/types/pipe.ts +84 -3
- package/types/stream.ts +82 -23
- package/build/services/durable/factory.d.ts +0 -17
- package/build/services/durable/factory.js +0 -817
- package/build/services/durable/meshos.d.ts +0 -127
- package/build/services/durable/meshos.js +0 -380
- package/services/durable/factory.ts +0 -818
- 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
|
|
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
|
-
|
|
37
|
-
|
|
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.
|
|
43
|
-
//
|
|
44
|
-
const subPipe = new Pipe(currentRow['@
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
84
|
-
|
|
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
|
|
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)
|
|
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 =
|
|
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] =
|
|
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
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* Optional Reason; will be used as the error `message` when thrown
|
|
107
|
+
* @default 'Job Interrupted'
|
|
108
|
+
*/
|
|
106
109
|
reason?: string;
|
|
107
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* throw JobInterrupted error upon interrupting
|
|
112
|
+
* @default true
|
|
113
|
+
*/
|
|
108
114
|
throw?: boolean;
|
|
109
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* Interrupt child/descendant jobs
|
|
117
|
+
* @default false
|
|
118
|
+
*/
|
|
110
119
|
descend?: boolean;
|
|
111
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Target job id (if not present the current job will be targeted)
|
|
122
|
+
*/
|
|
112
123
|
target?: string;
|
|
113
|
-
/**
|
|
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 = {
|